SoFunction
Updated on 2025-04-12

Lua coroutine program operation analysis

This is a piece of code that analyzes lua coroutine (coroutine) fromLua reference manual interface (Slightly modified):

Copy the codeThe code is as follows:

function foo (a)
    print("foo", a)
    return (2*a)
end

co = (function (a,b)
   print("co-body1", a, b)
   local r = foo(a+1)
   print("co-body2", r)
   local r, s = (a+b, a-b)
   print("co-body3", r, s)
   return b, "end"
end)

print("1----")
print("main", (co, 1, 10))
print("2----")
print("main", (co, "r"))
print("3----")
print("main", (co, "x", "y"))
print("4----")
print("main", (co, "x", "y"))


The operation effect is as follows:
Copy the codeThe code is as follows:

1------
co-body1    1   10
foo 2
main    true    4
2------
co-body2    r
main    true    11  -9
3------
co-body3    x   y
main    true    10  end
4------
main    false   cannot resume dead coroutine

There are a total of 4 calls to resume here, let's see how it works.

first:

Copy the codeThe code is as follows:

print("main", (co, 1, 10))

1. Execute print("co-body1", a, b) , the values ​​of a and b are provided as resume, a=1, b=10;
2. Calculate a+1=2, enter foo(a), and pass the calculation result just now through the a parameter, and execute print("foo", a);
3. Consider return (2*a);
4. Calculate 2*a=4, encounter yield, suspend the foo(a) call, and return 4 to resume. Note that foo's return has not been executed yet;
Execution is successful, return true, 4.

The second time:

Copy the codeThe code is as follows:

print("main", (co, "r"))

1. Start executing from the last pending foo(a) call, and then execute the unfinished return call;
2. Because yield returns the call parameter of resume, the value returned by foo(a+1) is the string "r". It's hard to understand here.
Because you may naturally think that the value of the local r variable should be the value of 2*a in yield(2*a).
It should be noted that the return value of yield is different from the value of yield parameter.
The former you can save it in a variable, either return it or not use it (not save the return result of yield); the latter is the return value of resume.
3. Execute print("co-body2", r) , the value of r is "r" ;
4. Consider local r, s = (a+b, a-b);
5. Calculate a+b=11, a-b=-9, encounter yield, suspend the call to co, and return 11 and 9 to resume. Note that the assignment of local r, s has not started yet.
What is not easy to understand here is why the value of a is not "r"? Because "r" has been consumed by the return value of yield above.
Execution is successful, return true, 11, -9.

The third time:

Copy the codeThe code is as follows:

print("main", (co, "x", "y"))

1. Start executing from the last yield, and then execute the unfinished local r, s = assignment. As mentioned above, yield will return the call parameter of resume, so the values ​​of r and s are "x" and "y";
2. Execute print("co-body3", r, s) to print;
3. Consider return b, "end";
The value of 10 has always been unchanged, and it is returned directly here, and the string "end" is also returned;
5. Since when a coroutine function returns, all its return values ​​are returned as resume's return value. Therefore, the resume here executes successfully, returning 10, "end" .

The fourth time:

Copy the codeThe code is as follows:

print("main", (co, "x", "y"))

Since the co function has returned, it is in the dead state and cannot resume, so the 4th resume fails.