一、
协同程序(coroutine)与多线程情况下的线程比较类似:有自己的堆栈,自己的局部变量,有自己的指令指针(IP,instruction pointer),但与其它协同程序共享全局变量等很多信息。
协程(协同程序): 同一时间只能执行某个协程。开辟多个协程开销不大。协程适合对某任务进行分时处理。
线程: 同一时间可以同时执行多个线程。开辟多条线程开销很大。线程适合多任务同时处理。
1.协程,即协作式程序,其思想是,一系列互相依赖的协程间依次使用CPU,每次只有一个协程工作,而其他协程处于休眠状态。协程实际上是在一个线程中,只不过每个协程对CUP进行分时,协程可以访问和使用unity的所有方法和component
2.线程,多线程是阻塞式的,每个IO都必须开启一个新的线程,但是对于多CPU的系统应该使用thread,尤其是有大量数据运算的时刻,但是IO密集型就不适合;而且thread中不能操作unity的很多方法和component
线程和协同程序的主要不同在于:在多处理器情况下,从概念上来讲多线程程序同时运行多个线程;而协同程序是通过协作来完成,在任一指定时刻只有一个协同程序在运行,并且这个正在运行的协同程序只在必要时才会被挂起。
二、
这里给出“进程、线程和协程”的特点:
- 进程:拥有自己独立的堆和栈,既不共享堆,也不共享栈,进程由操作系统调度;
- 线程:拥有自己独立的栈和共享的堆,共享堆,不共享栈,标准线程由操作系统调度;
- 协程:拥有自己独立的栈和共享的堆,共享堆,不共享栈,协程由程序员在协程的代码里显示调度。
接下来,以一个形象的例子,进一步讲述“进程、线程和协程”三者之间的区别:
假设有一个单核的操作系统,系统上没有其它的程序需要运行,现有两个线程 A 和 B,A 和 B 在单独运行时都需要 10 秒来完成自己的任务,而且任务都是运算操作,线程 A 和 B 之间没有竞争和共享数据的问题。现在让 A 和 B 两个线程并行,则操作系统会不停的在 A 和 B 两个线程之间切换,达到一种伪并行的效果。
如果操作系统切换的频率是每秒一次,切换的成本是 0.1 秒(主要是栈切换),则总共需要 20 + 19 * 0.1 = 21.9 秒;如果使用协程的方式,可以先运行协程 A,A 结束的时候让位给协程 B,只发生一次切换,则总共需要 20 + 1 * 0.1 = 20.1 秒。如果操作系统是双核的,而且线程是标准线程,那么线程 A 和 B 可以达到真的并行,则总时间为 10 秒;而协程的方式仍然需要 20.1 秒的时间。
三、
- 协程是属于线程的。协程程序是在线程里面跑的,因此协程又称微线程和纤程等
- 协没有线程的上下文切换消耗。协程的调度切换是用户(程序员)手动切换的,因此更加灵活,因此又叫用户空间线程.
- 原子操作性。由于协程是用户调度的,所以不会出现执行一半的代码片段被强制中断了,因此无需原子操作锁。
协程的实现:迭代器和生成器
- 迭代器: 实现了迭代接口的类,接口函数例如:current,key,next,rewind,valid。迭代器最基本的规定了对象可以通过next返回下一个值,而不是像数组,列表一样一次性返回。语言实现:在Java的foreach遍历迭代器对(数组),Python的for遍历迭代器对象(tuple,list,dist)。
- 生成器: 使用 yield 关键字的函数,可以多次返回值,生成器实际上也算是实现了迭代器接口(协议)。即生成器也可通过next返回下一个值。
协程举例:在Python中,使用了yield的函数为生成器函数,即可以多次返回值。则生成器可以暂停一下,转而执行其他代码,再回来继续执行函数往下的代码。
四、
协程属于线程,即一个线程下面可以开辟多个协程。
协程是用户态的轻量级线程。
协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈。
当多个协程切换时,由于其同属于一个线程,所以可以看作是同步执行的,不存在同时共享资源的情况,可以不加锁的访问全局变量,切换上下文非常快。
对于不需要cpu大量参与的业务场景来说,比如io广泛的业务,建议使用协程。
五、