###coroutine basics
The full name of the coroutine supported by Lua is called collaborative multithreading. Lua provides a separate run line for each coroutine. However, unlike multithreading, a coroutine is only suspended after explicitly calling the yield function, and only one coroutine is running at a time.
Lua puts all its coroutine functions into the coroutine table. The main functions are as follows
Extract a piece of Yunfeng 's code to explain the working mechanism of the coroutine in detail. In this code, the interaction between the main thread and the coroutine co is shown:
<!-- lang: lua --> function foo(a) print("foo", a) return coroutine.yield(2 * a) end co = 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"))
The following is the running result
co-body 1 10 foo 2 main true 4 co-body r main true 11, -9 co-body x y main false 10 end main false cannot resume dead coroutine
###coroutine and subroutine (subroutine) comparison
The start of a subroutine is the only entry point, and once return completes the execution of the subroutine, an instance of the subroutine will only run once.
But the coroutine is different. The coroutine can use yield to switch to other coroutines, and then reenter ** (reenter) through the resume method to the place where yield was last called, and pass the parameters of resume as the return value to the desired Reentrant coroutines. But none of the coroutine's state has been changed, 就像一个可以多次返回的subroutine
,
The subtlety of coroutines lies in 协作
this concept. Let's use the producer and consumer problems to demonstrate the basic application of coroutines. Note: The following pseudocode is written with Lua in mind
var q = queue ()
Producer's Pseudocode
loop while q is not full create product add the items to q resume to consumer
Consumer Pseudocode
loop while q is not empty consume product remove the items from q yield
###coroutine and callback comparison
Coroutine is often used to compare with callback, because in general, coroutine and callback can achieve the same function, namely asynchronous communication, such as the following example:
<!-- lang: lua --> bob.walkto(jane) bob.say("hello") jane.say("hello")
It seems to be right, but in fact, because these actions are walkto and say 需要一定时间才能做完的
, if this program is written in this way, it will cause bob to say hello to jane while walking, and then jane also says to bob at the same time hello, the whole process is very confusing.
If implemented using callbacks, the code example is as follows:
<!-- lang: lua --> bob.walto(function ( ) bob.say(function ( ) jane.say("hello") end,"hello") end, jane)
That is, the walto function calls back the say function, and the say function calls back the next say function, so the callback looks very confusing, making it impossible to see the meaning of this code at a glance.
If you use coroutine, you can use the following notation:
<!-- lang: lua --> co = coroutine.create(function ( ) local current = coroutine.running bob.walto(function ( ) coroutine.resume(current) end, jane) coroutine.yield() bob.say(function ( ) coroutine.resume(current) end, "hello") coroutine.yield() jane.say("hello") end) coroutine.resume(co)
In the above code, once an asynchronous function is called, the coroutine will use the coroutine.yield() method to temporarily suspend the coroutine, and add coroutine.resume(current) to the corresponding callback function to make it return to the current in the executing coroutine.
However, there are many repetitions in the above code, so the repeated code can be encapsulated by encapsulation
<!-- lang: lua --> function runAsyncFunc( func, ... ) local current = coroutine.running func(function ( ) coroutine.resume(current) end, ...) coroutine.yield() end coroutine.create(function ( ) runAsyncFunc(bob.walkto, jane) runAsyncFunc(bob.say, "hello") jane.say("hello") end) coroutine.resume(co)
In this way, it is not necessary to change all the previous callback functions, and the problem of asynchronous calls can be solved by means of Ctrip, which makes the structure of the code very clear.
Reprinted from: https://my.oschina.net/wangxuanyihaha/blog/186401