Bootstrap

13 协程设计原理与汇编实现

协程的问题

  1. 为什么要有协程?
  2. 协程的原语操作?
  3. 协程的切换?
  4. 协程的struct如何定义?
  5. 协程的scheduler(调度)如何定义?
  6. 调度策略如何实现?
  7. 协程如何与posix,api兼容?
  8. 协程多核模式?
  9. 协程的性能如何测试?

为什么要有协程

同步的编程方式,异步的性能。同步编程时,我们需要等待io就绪。但是在协程这里,我们使用一种机制,当io需要等待时,就切到下一个io,之后当之前的io就绪时,再切换回来继续处理就绪事件。

IO 异步操作与 IO 同步操作

同步/异步是用来形容两者之间的关系的
举个例子:这里有个dns服务器,还有一个dns客户端,假如我们向dns服务器发送50个请求,也就是我们发送发送50个域名,然后dns要返回50个ip地址。
同步就是我们向dns服务器请求一个,然后dns服务器返回一个。也就是这50个事串行的。
异步就是我们向dns服务器请求很多个,然后dns服务器有结果了就返回。也就是这50个事并行的。
在这里插入图片描述
从代码上看:
同步

sync(){
	send(request);
	recv(response);
}
response_cb(){//回调函数
	recv();
}
async(){
	send(request,response_cb);
}

异步有个缺点,send()和response()不是在一个流程里面,他可能有一个线程,或者有一个while()循环一直监视着是否可以调用response。所以可能send()和response()不是在一个线程里面。如果response中再调用回调的话,那么这个代码非常不利于人的阅读。

对比项 IO 同步操作 IO 异步操作
代码逻辑 程序整体逻辑清晰 子模块逻辑清晰
程序性能 响应时间长,性能差 响应时间短,性能好

所以同步编程简单,易于阅读。异步编程复杂,不太利于人的阅读。

再例如:检测io,读写,再一个流程里面。这里的同步和异步是说的检测io和读写io之间的关系。同步的性能是不如异步的。
7300ms,同步

while(1){
	epoll_wait();
	for(){
		recv();
		send();
	}
}

1600ms,异步

while(1){
	epoll_wait();
	for(){
		push_thread();
	}
}

在这里插入图片描述
所以同步编程简单,易于阅读。异步编程复杂,不太利于人的阅读。

所以有没有一种方式编程方式,拥有同步的编程方式,异步一样的性能。
协程就是这样的,我们写代码的时候看着是同步的,但是他底层是异步的。

async_Recv(fd,buffer,length){
	ret=poll(fd);//是否就绪
	epoll_ctl(add);//就是就绪了之后能切换回来。
	switch(next_fd);//不就绪就切换
}
async_Send(fd,buffer,length){
	ret=poll(fd);//是否就绪
	epoll_ctl(add);
	switch(next_fd);//不就绪就切换
}

while(1){
	epoll_wait();
	for(){
		async_Recv(fd,buffer,length);
		parse(buffer);
		async_Send(fd,buffer,length);
	}
}

就是处理的时候,如果没有就绪就切换到下一个,然后将当前这个加入到epoll中,如果这个就绪了,方便下次处理这个。
这里的切出用yield,回来用resume.

协程的原语操作

协程的核心原语操作:create, resume, yield。
两个,一个让出,一个切换回来

yield(from,to);//这个是切出
resume(to,from);//这个是回来

create:创建一个协程。

  1. 调度器是否存在,不存在也创建。调度器作为全局的单例。将调度
    器的实例存储在线程的私有空间 pthread_setspecific。
  2. 分配一个 coroutine 的内存空间,分别设置 coroutine 的数据
    项,栈空间,栈大小,初始状态,创建时间,子过程回调函数,子
    过程的调用参数。
  3. 将新分配协程添加到就绪队列 ready_queue 中

yield: 让出 CPU。

void nty_cor
;