成都創(chuàng)新互聯(lián)主打移動網(wǎng)站、網(wǎng)站設(shè)計、成都網(wǎng)站設(shè)計、網(wǎng)站改版、網(wǎng)絡(luò)推廣、網(wǎng)站維護、域名與空間、等互聯(lián)網(wǎng)信息服務(wù),為各行業(yè)提供服務(wù)。在技術(shù)實力的保障下,我們?yōu)榭蛻舫兄Z穩(wěn)定,放心的服務(wù),根據(jù)網(wǎng)站的內(nèi)容與功能再決定采用什么樣的設(shè)計。最后,要實現(xiàn)符合網(wǎng)站需求的內(nèi)容、功能與設(shè)計,我們還會規(guī)劃穩(wěn)定安全的技術(shù)方案做保障。
協(xié)程這個概念很久了,好多程序員是實現(xiàn)過這個組件的,網(wǎng)上關(guān)于協(xié)程的文章,博客,論壇都是汗牛充棟,在知乎,github上面也有很多大牛寫了關(guān)于協(xié)程的心得體會。突發(fā)奇想,我也來實現(xiàn)一個這樣的組件,并測試了一下性能。借鑒了很多大牛的思想,閱讀了很多大牛的代碼。于是把整個思考過程寫下來。實現(xiàn)代碼?https://github.com/wangbojing/NtyCo
代碼簡單易讀,如果在你的項目中,NtyCo能夠為你解決些許工程問題,那就榮幸之至。
下面將部分的NtyCo的代碼貼出來。
NtyCo 支持多核多進程。
int?process_bind(void)?{ int?num?=?sysconf(_SC_NPROCESSORS_CONF); pid_t?self_id?=?syscall(__NR_gettid); printf("selfid?-->?%d\n",?self_id); cpu_set_t?mask; CPU_ZERO(&mask); CPU_SET(self_id?%?num,?&mask); sched_setaffinity(0,?sizeof(mask),?&mask); mulcore_entry(9096?+?(self_id?%?num)?*?10); }
NtyCo 上下文切換
首先來回顧一下x86_64寄存器的相關(guān)知識。x86_64 的寄存器有16個64位寄存器,分別是:%rax, %rbx, %rcx, %esi, %edi, %rbp, %rsp, %r8, %r9, %r10, %r11, %r12,
%r13, %r14, %r15。
%rax作為函數(shù)返回值使用的。
%rsp棧指針寄存器,指向棧頂
%rdi, %rsi, %rdx, %rcx, %r8, %r9用作函數(shù)參數(shù),依次對應(yīng)第1參數(shù),第2參數(shù)。。。
%rbx, %rbp, %r12, %r13, %r14, %r15用作數(shù)據(jù)存儲,遵循調(diào)用者使用規(guī)則,換句話說,就是隨便用。調(diào)用子函數(shù)之前要備份它,以防它被修改
%r10, %r11用作數(shù)據(jù)存儲,就是使用前要先保存原值。
?
上下文切換,就是將CPU的寄存器暫時保存,再將即將運行的協(xié)程的上下文寄存器,分別mov到相對應(yīng)的寄存器上。此時上下文完成切換。如下圖所示:
代碼如下
__asm__?( "????.text??????????????????????????????????\n" "???????.p2align?4,,15???????????????????????????????????\n" ".globl?_switch??????????????????????????????????????????\n" ".globl?__switch?????????????????????????????????????????\n" "_switch:????????????????????????????????????????????????\n" "__switch:???????????????????????????????????????????????\n" "???????movq?%rsp,?0(%rsi)??????#?save?stack_pointer?????\n" "???????movq?%rbp,?8(%rsi)??????#?save?frame_pointer?????\n" "???????movq?(%rsp),?%rax???????#?save?insn_pointer??????\n" "???????movq?%rax,?16(%rsi)??????????????????????????????\n" "???????movq?%rbx,?24(%rsi)?????#?save?rbx,r12-r15???????\n" "???????movq?%r12,?32(%rsi)??????????????????????????????\n" "???????movq?%r13,?40(%rsi)??????????????????????????????\n" "???????movq?%r14,?48(%rsi)??????????????????????????????\n" "???????movq?%r15,?56(%rsi)??????????????????????????????\n" "???????movq?56(%rdi),?%r15??????????????????????????????\n" "???????movq?48(%rdi),?%r14??????????????????????????????\n" "???????movq?40(%rdi),?%r13?????#?restore?rbx,r12-r15????\n" "???????movq?32(%rdi),?%r12??????????????????????????????\n" "???????movq?24(%rdi),?%rbx??????????????????????????????\n" "???????movq?8(%rdi),?%rbp??????#?restore?frame_pointer??\n" "???????movq?0(%rdi),?%rsp??????#?restore?stack_pointer??\n" "???????movq?16(%rdi),?%rax?????#?restore?insn_pointer???\n" "???????movq?%rax,?(%rsp)????????????????????????????????\n" "???????ret??????????????????????????????????????????????\n" );
協(xié)程的調(diào)度器
調(diào)度器的實現(xiàn),有兩種方案,一種是生產(chǎn)者消費者模式,另一種多狀態(tài)運行。
邏輯代碼如下:
while?(1)?{ ? ????????//遍歷睡眠集合,將滿足條件的加入到ready ????????nty_coroutine?*expired?=?NULL; ????????while?((expired?=?sleep_tree_expired(sched))?!=?)?{ ????????????TAILQ_ADD(&sched->ready,?expired); ????????} ? ????????//遍歷等待集合,將滿足添加的加入到ready ????????nty_coroutine?*wait?=?NULL; ????????int?nready?=?epoll_wait(sched->epfd,?events,?EVENT_MAX,?1); ????????for?(i?=?0;i?ready,?wait); ????????} ? ????????//?使用resume回復(fù)ready的協(xié)程運行權(quán) ????????while?(!TAILQ_EMPTY(&sched->ready))?{ ????????????nty_coroutine?*ready?=?TAILQ_POP(sched->ready); ????????????resume(ready); ????????} ????}
多狀態(tài)運行
實現(xiàn)邏輯代碼如下:
while?(1)?{ ? ????????//遍歷睡眠集合,使用resume恢復(fù)expired的協(xié)程運行權(quán) ????????nty_coroutine?*expired?=?NULL; ????????while?((expired?=?sleep_tree_expired(sched))?!=?)?{ ????????????resume(expired); ????????} ? ????????//遍歷等待集合,使用resume恢復(fù)wait的協(xié)程運行權(quán) ????????nty_coroutine?*wait?=?NULL; ????????int?nready?=?epoll_wait(sched->epfd,?events,?EVENT_MAX,?1); ????????for?(i?=?0;i?ready))?{ ????????????nty_coroutine?*ready?=?TAILQ_POP(sched->ready); ????????????resume(ready); ????????}
性能測試
測試環(huán)境:4臺VMWare 虛擬機
1臺服務(wù)器 6G內(nèi)存,4核CPU
3臺客戶端 2G內(nèi)存,2核CPU
操作系統(tǒng):ubuntu 14.04
服務(wù)器端測試代碼:https://github.com/wangbojing/NtyCo
客戶端測試代碼:https://github.com/wangbojing/c1000k_test/blob/master/client_mutlport_epoll.c
?
按照每一個連接啟動一個協(xié)程來測試。協(xié)程啟動數(shù)量能夠達70W無異常。
????BAT, 滴滴,今日頭條,美圖,美團等一線內(nèi)推 技術(shù)崗位內(nèi)推?
????QQ群:935760465