协程的实现依赖于时间片的分隔
协程就是用户态的线程”,Lua协程是非抢占式的多线程,必须手动在不同的协程间切换,且同一时刻只能有一个协程在运行,相当于单线程的能力。线程确实比协程的性能更好,因为线程能利用多核达到真正的并行计算,
要理解是什么是“用户态的线程”,必然就要先理解什么是“内核态的线程”。 内核态的线程是由操作系统来进行调度的,在切换线程上下文时,要先保存上一个线程的上下文,然后执行下一个线程,当条件满足时,切换回上一个线程,并恢复上下文。 协程也是如此,只不过,用户态的线程不是由操作系统来调度的,而是由程序员来调度的,是在用户态的。
yield
这个关键字就是用来产生中断, 并保存当前的上下文的, 比如说程序的一段代码是访问远程服务器,那这个时候CPU就是空闲的,就用yield
让出CPU,接着执行下一段的代码,如果下一段代码还是访问除CPU以外的其它资源,还可以调用yield
让出CPU. 继续往下执行,这样就可以用同步的方式写异步的代码了.
优点:
1.无需线程上下文切换的开销
2.无需原子操作锁定及同步的开销
3.方便切换控制流,简化编程模型
4.高并发+高扩展性+低成本:一个CPU支持上万的协程都不是问题。所以很适合用于高并发处理
缺点:
1.无法利用多核资源:协程的本质是个单线程,它不能同时将 单个CPU 的多个核用上,协程需要和进程配合才能运行在多CPU上.当然我们日常所编写的绝大部分应用都没有这个必要,除非是cpu密集型应用。
2.进行阻塞操作(如IO读写时)会阻塞掉整个程序
协程的应用多在于异步+回调方式:
function readsome() io.read();--若不输入则io阻塞 print("yield before"); coroutine.yield(); print("yield after"); end local co=coroutine.create(readsome); coroutine.resume(co); print("contine "); coroutine.resume(co);
--yield before
--contine?
--yield after三个状态:suspended(挂起,协同刚创建完成时或者yield之后)、running(运行)、dead(函数走完后的状态,这时候不能再重新resume)。
coroutine.create(arg):根据一个函数创建一个协同程序,参数为一个函数
coroutine.resume(co):使协同从挂起变为运行(1)激活coroutine,也就是让协程函数开始运行;(2)唤醒yield,使挂起的协同接着上次的地方继续运行。该函数可以传入参数
coroutine.status(co):查看协同状态
coroutine.yield():使正在运行的协同挂起,可以传入参数
coroutine.running: 返回当前的协程,如果它被主线程调用的话,返回nil