Concurrency is the essential characteristics of the real world, and smart computer scientists use the technical means of simulating concurrency, the multitasking mechanism. There are roughly two multi-tasking techniques, one is a preemptive multitasking, which allows the operating system to decide which task is executed. Another kind is a collaborative multitasking, which gives the decision to the task, allowing them to voluntarily give up the execution when they think they are appropriate. These two multi-tasking methods have advantages and disadvantages, and the inherent synchronization problem in the former makes the program often have unpredictable behavior, while the latter requires the task to have a considerable self-discipline.
Coroutine technology is a program control mechanism that has been proposed in the 1960s and can be easily collaborative multitasking. In mainstream programming languages (such as C , Java, Pascal, etc. we rarely see the figure of the sweeper, but now there are many dynamic scripting languages (PYTHON, Perl) provides a mechanism similar to the same. The most prominent is Lua.
The extension of Lua language is an asymmetric solution, or a Semi-Symmetric strike, or simi-coroutine. The reason why this advantageous mechanism is called unmoid because it provides two operations of two password control: one is (heavy) calling sweeper (via COROUTINE.RESUME); the other is hang The weighing and returns the program control to the caller (via Coroutine.yield). An asymmetric sweeper can be seen as a caller from its caller, and the relationship between the two is very similar to the relationship between routine and its caller. Since there is a non-symmetrical equilation, there is of course a symmetric (Symmetric), it is characterized by only one operation of the transfer program control, so that the control is directly transmitted to the specified sweep. There have been such a saying that the ability of symmetrical and non-symmetrical equilation mechanisms is not equivalent, but in fact, it is easy to implement the latter according to the former. Next, we use the code to prove this fact.
- Symmetrical Corporate Coro.lua
- The code is taken from the paper "Coroutines in Lua" - www.inf.puc-rio.br/~roberto/docs/corosblp.pdf
Coro = {} - Coro.main Used to identify the principal function of the program Coro.main = function () end - Coro.current variable to identify the agreement with control, - that is, the current extension is running Coro.current = coro.main
- Create a new advantage of Function Coro.create (f) Return Coroutine.Wrap (Function (VAL) RETURN NIL, F (VAL) End) end
- Transfer control and designated data VAL pass to the fight against KFunction Coro.Transfer (K, VAL) if coro.current ~ = coro.main the return corordine.yield (k, val) Else - Control Dress Dispatching WHILE K DO Coro.current = k if k == Coro.main Then Return Val End K, VAL = K (VAL) End Error ("Coroutine Ended WITHOUT TRANSFERING CONTROL ..." Endend
If you don't understand the above procedures, it doesn't matter, look at how to use this library and then look back. Here is an example: Require ("Coro.lua")
Function foo1 (n) Print ("1: foo1 received value" ..n) n = coro.transfer (foo2, n 10) print ("2: foo1 received value" ..n) n = coro.transfer (Coro .MAIN, N 10) Print ("3: foo1 received value" ..n) Coro.Transfer (Coro.main, N 10) End
Function Foo2 (N) Print ("1: foo2 received value" ..n) n = coro.transfer (coro.main, n 10) Print ("2: foo2 received value" ..n) Coro.Transfer (Foo1 , N 10) end
FUNCTION main () foo1 = coro.create (foo1) foo2 = coro.create (foo2) local n = coro.transfer (foo1, 0) Print ("1: main received value" .n) n = coro.transfer FOO2, N 10) Print ("2: main received value" ..n) n = coro.transfer (foo1, n 10) Print ("3: main received value" ..n) End
- Set Main to the main function (Agreement) Coro.main = main - set coro.main to the current price Coro.current = coro.main - Start execution of the main function (between the other) Coro.main ()
The above example defines a main function called Main, and the entire program is started by it, but it is ended due to it. Why do you need such a master? The above is said, program control can be freely passed directly between the symmetrical scales. It does not matter who is in the same level, but the application must have a start point, so we define one The main function allows it to ignite the outflow line running. Although all the advantages are equal, it is still a special position as the main function of the procedure running power (which is absolute equality in this world!), For this purpose, our library has specially used a coro.main variable to save the main Functions, and set it to the current sweeper before it is executed (although the main MAIN actually is just a normal function rather than a real fight, this is not much related, and the main function is also called the main function. Channel). The result of the example run is:
1: foo1 received value 01: foo2 received value 101: main received value 202: foo2 received value 302: foo1 received value 402: main received value 503: foo1 received value 603: main received value 70
The execution sequence of the weigh is: main-> foo1-> foo2-> main-> foo2-> foo1-> main-> foo1-> main.
The Coro.Transfer (k, val) function is a sweeper that will receive program control, while Val is data passed to K. If the current sweeper is not a primary advantage, Tansfer (k, val) simply uses Coroutine.Yield (k, val) to pending the current sweeper and transmitting two data, namely the next stop and delivery of the program control. Give it the data; otherwise enter a control power (DISPATCH) loop, the loop (heavy) start (Resume) K, waiting to be executed to the suspend, and the data returned back according to this point Determine the next level to be started to start. From the application example, the advantages of the co-trip and the weighing seems to be transferred directly with Transfer, but in fact this delivery is passed. Each TRANSFER that is called (comparing Coro.current and Coro.main if it can be determined) is equivalent to an extension manager, which constantly (heavy) start an agreement and will control Hand, then wait for the sweep to hung up, and then (again) start the next sweeping .... This action will not stop unless <1> will (heavy) the advantage of the (heavy) Proto-equilation; <2> A top destination is not provided by a certain level. Obviously, every round of dispatching cycles is grasped by the main stroke, and if the next stop in the loop, the next stop is the main agreement, which means that this main agreement will be handed out. The TRANSFER operation should be over, so the function returns to VAL to end this round of cycling. For the case <2>, the body function (Body function) created because Coro.create (f) is actually FUNCTION (VAL) RETURN NIL, F (VAL) End, so when the last instruction of the function f is not transfeer This sweep will eventually be executed and return the NIL and the return value of the function F. If K is such a sweep, the TRANSFER executes the k, the Val = k (VAL) statement, the k value is NIL, which is considered an error, because the program is not determined at this time that the next (heavy) started Who is the extension? So under the symmetrical model, each of the advantages (Of course, the primary proposal is outdated), and it must be explicitly passed to other sweeping. According to the above analysis, the assignment of the control of the application should be: first round of dispatch: main-> foo1-> main-> foo2-> main-> main (end) second round dispatch: main-> foo2-> main -> foo1-> main-> main (end) third round dispatch: main-> foo1-> main-> main (end)
Since the target of control transfer can be directly specified, the symmetrical equilation mechanism has great freedom, but the cost of this freeness is the sacrifice structure. If the program is slightly complicated, even very experienced programmers are hard to grasp the procedure process. This is very similar to the goto statement, which allows the program to jump to any way you want to go, but people are difficult to understand the procedures filled with Goto. The non-symmetrical equilation has a good hierarchical structure relationship, (again) Starting these sweepers and call a function very similar: (heavy) start-up sweeping to get control start execution, then hang (or end) and will Control returns to the scalabers, which is completely consistent with the structured programming style advocated by the computers.
In summary, Lua provides the asymmetric score of the LUA not only has the same power as the symmetric trip, but also avoids the programmer's abuse mechanism to write the structure of the structure.