网络IO解决方案 — 协程框架的实现
admin
2023-03-09 12:01:08
0


网络IO解决方案 — 协程框架的实现


协程这个概念很久了,好多程序员是实现过这个组件的,网上关于协程的文章,博客,论坛都是汗牛充栋,在知乎,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 的寄存器有1664位寄存器,分别是:%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到相对应的寄存器上。此时上下文完成切换。如下图所示:


网络IO解决方案 — 协程框架的实现



代码如下

__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"
);


协程的调度器

调度器的实现,有两种方案,一种是生产者消费者模式,另一种多状态运行。

网络IO解决方案 — 协程框架的实现


逻辑代码如下:

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);
        }
    }


多状态运行

网络IO解决方案 — 协程框架的实现

实现逻辑代码如下:

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无异常。



网络IO解决方案 — 协程框架的实现


网络IO解决方案 — 协程框架的实现



    BAT, 滴滴,今日头条,美图,美团等一线内推 技术岗位内推 

    QQ群935760465


相关内容

热门资讯

终于懂了“微乐捉鸡麻将.真的有... 有 亲,根据资深记者爆料微乐捉鸡麻将是可以开挂的,确实有挂(咨询软件无需...
【第一消息】“战皇炸金花.有挂... 【第一消息】“战皇炸金花.有挂吗?”必胜开挂神器您好,战皇炸金花这个游戏其实有挂的,确实是有挂的,需...
终于明白“冷酷炸金花.究竟有挂... 有 亲,根据资深记者爆料冷酷炸金花是可以开挂的,确实有挂(咨询软件无需打...
【第一消息】“喜扣游戏.怎么开... 【第一消息】“喜扣游戏.怎么开挂?”透视曝光猫腻您好,喜扣游戏这个游戏其实有挂的,确实是有挂的,需要...
【第一资讯】“西兵互娱.是不是... 您好:西兵互娱这款游戏可以开挂,确实是有挂的,需要了解加客服微信【4282891】很多玩家在这款游戏...
玩家攻略科普“冷酷牛牛.真的有... 玩家攻略科普“冷酷牛牛.真的有挂吗?”透视曝光猫腻您好,冷酷牛牛这个游戏其实有挂的,确实是有挂的,需...
玩家最新攻略“蜀友汇.有没有挂... 家人们!今天小编来为大家解答蜀友汇透视挂怎么安装这个问题咨询软件客服徽9752949的挂在哪里买很多...
小红书、微博狂晒征信,到底哪些... 作者:杜川央行一次性个人信用修复政策落地后,社交平台迅速掀起讨论热潮。近两日,在小红书、微博上,大量...
终于明白“荊州晃晃麻将.辅助开... 网上科普关于“荊州晃晃麻将有没有挂”话题很是火热,小编也是针对荊州晃晃麻将作*弊开挂的方法以及开挂对...
强生爽身粉致癌案被判赔女子11... 快科技12月24日消息,央视财经报道,当地时间22日,美国马里兰州一陪审团裁定,强生公司需向一名因使...