
協程這個概念很久了,好多程序員是實現過這個組件的,網上關于協程的文章,博客,論壇都是汗牛充棟,在知乎,github上面也有很多大牛寫了關于協程的心得體會。突發奇想,我也來實現一個這樣的組件,并測試了一下性能。借鑒了很多大牛的思想,閱讀了很多大牛的代碼。于是把整個思考過程寫下來。實現代碼?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寄存器的相關知識。x86_64 的寄存器有16個64位寄存器,分別是:%rax, %rbx, %rcx, %esi, %edi, %rbp, %rsp, %r8, %r9, %r10, %r11, %r12,
%r13, %r14, %r15。
%rax 作為函數返回值使用的。
%rsp 棧指針寄存器,指向棧頂
%rdi, %rsi, %rdx, %rcx, %r8, %r9 用作函數參數,依次對應第1參數,第2參數。。。
%rbx, %rbp, %r12, %r13, %r14, %r15 用作數據存儲,遵循調用者使用規則,換句話說,就是隨便用。調用子函數之前要備份它,以防它被修改
%r10, %r11 用作數據存儲,就是使用前要先保存原值。
?
上下文切換,就是將CPU的寄存器暫時保存,再將即將運行的協程的上下文寄存器,分別mov到相對應的寄存器上。此時上下文完成切換。如下圖所示:

代碼如下
__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" );
協程的調度器
調度器的實現,有兩種方案,一種是生產者消費者模式,另一種多狀態運行。

邏輯代碼如下:
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?<?nready;i?++)?{
????????????wait?=?wait_tree_search(events[i].data.fd);
????????????TAILQ_ADD(&sched->ready,?wait);
????????}
?
????????//?使用resume回復ready的協程運行權
????????while?(!TAILQ_EMPTY(&sched->ready))?{
????????????nty_coroutine?*ready?=?TAILQ_POP(sched->ready);
????????????resume(ready);
????????}
????}多狀態運行

實現邏輯代碼如下:
while?(1)?{
?
????????//遍歷睡眠集合,使用resume恢復expired的協程運行權
????????nty_coroutine?*expired?=?NULL;
????????while?((expired?=?sleep_tree_expired(sched))?!=?)?{
????????????resume(expired);
????????}
?
????????//遍歷等待集合,使用resume恢復wait的協程運行權
????????nty_coroutine?*wait?=?NULL;
????????int?nready?=?epoll_wait(sched->epfd,?events,?EVENT_MAX,?1);
????????for?(i?=?0;i?<?nready;i?++)?{
????????????wait?=?wait_tree_search(events[i].data.fd);
????????????resume(wait);
????????}
?
????????//?使用resume恢復ready的協程運行權
????????while?(!TAILQ_EMPTY(sched->ready))?{
????????????nty_coroutine?*ready?=?TAILQ_POP(sched->ready);
????????????resume(ready);
????????}性能測試
測試環境:4臺VMWare 虛擬機
1臺服務器 6G內存,4核CPU
3臺客戶端 2G內存,2核CPU
操作系統:ubuntu 14.04
服務器端測試代碼:https://github.com/wangbojing/NtyCo
客戶端測試代碼:https://github.com/wangbojing/c1000k_test/blob/master/client_mutlport_epoll.c
?
按照每一個連接啟動一個協程來測試。協程啟動數量能夠達70W無異常。


????BAT, 滴滴,今日頭條,美圖,美團等一線內推 技術崗位內推?
????QQ群:935760465
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。