协程的实现,及其我们为什么用协程

1)为什么要有协程?

2)客户端的同步和异步
    1.客户端的同步:发送一个请求,等待服务器端的返回。如:请求Redis,等待返回value
        缺点: 每一秒钟客户端请求服务器的数量不会很多。

    2.客户端的异步:不停的提交。


    结论:客户端使用异步,速度远远快于同步。

3)king式四元组:
    1.init 
    2.commit
    3.callback
    4.destroy 

4)服务器端的同步与异步(以增加1000连接为例子)
    (1)同步: 5.6s
        epoll进行读写是否就绪的监听,并且recv和send在一个流程里面,则叫同步。

    (2)异步: 0.8s
        实现:epoll监听到读写事件,包装为任务,扔到线程池中,
            线程池中进行recv与send。

        定义:epoll事件感应和recv、send不在一个线程中,这叫异步。

5)2个口语词
    (1)异步IO: AIO的模式,有数据了直接回调。

    (2)IO异步操作:多线程异步\多线程同步

6)同步/异步 与 协程有什么关系?
    (1)知乎上的回答:用同步的编程方式,异步的。。。

    (2)同步和异步是在形容2者之间的关系。 如果找不到2者,请用:阻塞与非阻塞。


    同步的优点:读完后解析,符合人线性化的思维。

    异步:
        多个客户端连接服务器。
        一个客户端发出一个IO事件:“你好”。
        检测一个IO事件,服务器把这个IO事件push到另外一个线程里面。
        这时,再次发送一个“你好1”。
        又收到。。。多个线程共用一个fd的线程--》脏数据。--》对fd进行加锁--》不利于我们代码写逻辑。

        同步的编程方式,更符合我们的思维,更加的直观。但是同步的性能不高,没有异步的好。

    目的:有没有同步的编程方式,却有异步的性能?

    协程是如何解决这个问题的?

7)目标:
    (1)现在:客户端一下子能提交多个请求。
       慢慢的等待服务器端的返回。--》返回是在另外一个callback处理。
    
    (2)目标:多个请求,看起来是同步的等待返回。 但是却拥有异步的性能。==》如何实现?

8)实现跳转的3种方法(类似于goto的语句,是函数内部跳用)
    1.setjump/longjmp: 跨越函数栈的跳转。 -->c的标准接口
    2.ucontext: 系统上下文的跳转。-->linux的接口
    3.自己用汇编来实现:跳转。--》go的底层实现也是汇编。

    封装为2个原语操作:
        yield: jump-->pos   (commit后,让出cpu,依赖于epoll,到callback函数里面去,callback执行完后,就resume回到执行过程。)
        resume: jump-->back  ==》什么时候调用是由epoll控制的。
        switch:  采用汇编来实现。 用几个寄存器保存上下文。

9)如何实现跳转?
    2个CPU的上下文切换:
        一个CPU,上面保存了16个寄存器。

    线程1在运行。 保存线程1里面寄存器的值(store),加载线程2里面的值(load),这就是线程上下文的切换。

    eax,ebx...

10)如何保存寄存器里面的值?

11)协程的出现:
    实现这样一个框架:降低编程难度。同步的写法,异步的性能。 让出CPU,同时依赖于epoll,实现流程的切换。

================

1)封装为协程后的
    从客户端提交请求-->callback函数返回数据,是在一个调度单元里面的。

    epoll时,让出cpu,让epoll检测是否有数据:
        有数据:recv,recv完毕后,切换回来。
        没有:

2)之前:
    主线程一直commit,另外一个线程等待结果的返回。

    现在: 提交请求,让出cpu--》切换到另外一个线程的。

    IO密集型的情况下,协程可以完全替代线程。

    服务器计算结果,协程不能代替线程。不是强计算。 

3)如何定义 ‘协程’ 结构体
    1.cpu_ctx
    2.status(ready,running,defer)
    3.func: 入口函数
    4.arg
    5.stack栈空间: 为什么是必要的? ==》让每一个协程 “独立” 的根本。==》sp指针--》指向的位置 就是栈--》接下来CPU帮助你处理。
        是独立的,而不是共用的。

    6.stack_size

    一个调度器,调度N多个协程。每一个有着不同的状态。
    当前运行着是哪个协程。 多个就绪,多个休眠--》但是只有一个在运行。

4)'调度器'的定义
    1.cur_ctx
    2.set<ready>
    3.set<defer>
    4.epfd

5)
    同步: 1个请求,一个回应。
    异步: 发一个请求,再发一个请求。
    同步写法,异步性能: 发一个请求,让出CPU,跳转到接收的地方。判断IO是否有数据,没有数据,再切换回来。 
        一定是有很多的异步请求,才有必要。

        提交请求的地方,叫做让出CPU,跳到:recv这。。处理完,再跳回来。 ==》其实表面是同步的,底层依然是:异步的。 

6)

   结构。调用和关闭是托管使用的。
   入口函数。
   协程的参数 


   线程: id, NULL, server, port 

   coroutine_create: 分配一个couroutine,并且加入到就绪队列ready里面。 并不是开始运行了,只有调度器调度到此能运行。

   run: 调度器的开始执行。

7)coroutine:协程 
   1.cpu上下文,寄存器组
   2.协程的入口函数
   3.参数
   4.栈大小
   5.处于一个什么状态(就绪N、等待N、休眠N、退出N--》集合)
   6.就绪集合--》一个元素。 队列   --》
   7.等待集合--》一个元素。 队列。(超时时间,则可以用红黑树)
   8.休眠集合--》一个元素。 红黑树 --》    等待某个条件的满足。 -->一次性超出多个。
   

   一个协程,在多个集合里面是完全有可能的。

8)Timer的实现
   最小堆、红黑树、时间轮

9)调度器的定义
    1.当前运行的哪个协程。--》方便我们yield(sched->cur, sched->cur->next)操作。
    2.epfd: 整个协程调度的最原始的动力。 


    全局变量--》加到调度器里。
    每个协程特有的加到协程里面。


10)
    ntyco提供的api。
    schedule_run调度的方法。


    有多个地方调用recv,则切换跳到另外一个recv的地方。 直到找到fd准备就绪了。--》这样让recv函数本身就是异步的。==》同步的recv改为异步的recv。

11)核心点: nty_poll_inner
        将fd加到epoll里面。--》

12)跳转的核心的点:
    nty_coroutine_yield 

13)在recv之前,将fd加入到全局epoll里面。     nty_recv、nty_send、nty_connect、nty_accept
    1.fd--》epoll
    2.yield   ==>


    调度器:master主线程,不属于任何一个coroutine      co1    co2   co3    co4

        向左是yield,,向右是resume


        并不是由线程1到线程2,而是线程1切换到调度器里面。 然后调度器再切换到线程2.


    调度器里面执行的全部是resume函数。

    在协程里面执行的全部是yield函数。


14)没有东西加入到epoll里面,则会阻塞。

   先create,再调用schedule_run, 否则就直接退出了。

15)co被创建出来的时候,一次都没有运行的时候,是如何被第一次运行的,入口点在哪里?
      co->ctx.eip=_exec;


   IO密集型的操作,底层核心是epoll在驱动着调度器调度。

=========
多个IO可读写的话:处理完一个,返回到调度器,调度器再调度下一个。

==========多核
1.借助线程。
    a.所有的线程共用一个调度器;
    b.每个线程一个调度器;

2.借助进程。


=================CPU的粘合
每个CPU上都有一个调度队列。

绑定CPU:这个进程只在这个CPU上执行。

================

其实协程的性能,并不比:epoll+多线程的方式高,毕竟协程内部还是依赖于epoll。

使用最主要的原意是:简单,容易维护!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值