明天咱们先来看下lua手册上一个协程实例:
手册实例:
function foo(a) print("foo", a) return coroutine.yield(2 * a)endco = coroutine.create(function ( a, b ) print("co-body", a, b) local r = foo(a + 1) print("co-body", r) local r, s = coroutine.yield(a + b, a - b) print("co-body", r, s) return b, "end"end)print("main", coroutine.resume(co, 1, 10))print("main", coroutine.resume(co, "r"))print("main", coroutine.resume(co, "x", "y"))print("main", coroutine.resume(co, "x", "y"))
执行后果:
co-body 1 10 -- 协程co的第7行,此时resume()传入的参数是赋值给了函数的foo 2 -- 在第8行外面调用了函数foo(),执行到第2行的打印main true 4 -- 因为函数foo()的第3行yield()执行后挂起,参数是4,作为第15行的resume()的第二个返回值,最终打印了进去,到此,第15行执行结束co-body r -- 第16行resume()再次唤醒协程co,接着上次yield()的中央继续执行,参数“r"被赋值给上次yield()的返回值,在第9行打印进去main true 11 -9 -- 在第10行yiled()后再次挂起协程co,并返回,此时参数a和b还是第一次resume()时的参数,1,10,所以yield()两个参数别离为11,-9,作为resum()的第二个返回值,最终被打印进去,到此,第16行执行结束co-body x y -- 第17行resume()再次唤醒协程co,传入的参数“x”,“y”被赋值给上次的yield()函数的返回值,即赋值给第10行的r,s,在第11行被打印进去main true 10 end -- 协程co在第12行返回,留神此时参数b依然是第一次resume()时的参数2,值为10,至此协程co执行完结,变为dead状态,最终在第17行打印进去main false cannot resume dead coroutine -- 第18行尝试再次resume()协程co,因为协程co曾经为dead状态,所以间接返回并报错
下面这个实例很好的展现了coroutine.yield和coroutine.resume之间的相互作用。协程在生产者和消费者问题上应该用也比拟宽泛,咱们来看看上面这个例子。
生产者与消费者:
coConsume = coroutine.create( function () while true do local stutas, msg = coroutine.resume(coProducer) print('receive msg : ', msg) coroutine.resume(coProducer, string.len(msg)) end end)coProducer = coroutine.create( function () while true do local msg = io.read() local len = coroutine.yield(msg) print('he tell me he has recved data len is ', len) coroutine.yield() end end)coroutine.resume(coConsume)
运行后果:
hello --从键盘输入receive msg : hellohe tell me he has recved data len is 5
下面这个实例有两个协程,一个是生产协程次要是从屏幕上接管输出的数据,另外一个是消费者,解决承受到的信息将其打印。
总结:
最初援用知乎上的一段话作为协程学习的一个小结。
在IO密集型的程序中因为IO操作远远小于CPU的操作,所以往往须要CPU去等IO操作。同步IO下零碎须要切换线程,让操作系统能够在IO过程中执行其余的货色。这样尽管代码是合乎人类的思维习惯然而因为大量的线程切换带来了大量的性能的节约,尤其是IO密集型的程序。
所以人们创造了异步IO。就是当数据达到的时候触发我的回调。来缩小线程切换带来性能损失。然而这样的害处也是很大的,次要的害处就是操作被 “分片” 了,代码写的不是 “零打碎敲” 这种。 而是每次来段数据就要判断 数据够不够解决哇,够解决就解决吧,不够解决就在等等吧。这样代码的可读性很低,其实也不合乎人类的习惯。
然而协程能够很好解决这个问题,比方 把一个IO操作 写成一个协程。当触发IO操作的时候就主动让出CPU给其余协程。要晓得协程的切换很轻的。协程通过这种对异步IO的封装 既保留了性能也保障了代码的 容易编写和可读性。在高IO密集型的程序下很好,然而高CPU密集型的程序下没啥益处。