Lua - Nested Coroutines
Nesting coroutines refers to creating coroutine(s) during a coroutine execution, resuming other coroutine and so. Nesting coroutines allows to create complex workflows. In this chapter, we're discussing the ways to handle coroutine nesting and implications.
Example - Creation and Resumption within Coroutine
Let's look at an example to understand the concept of nesting of coroutines.
main.lua
-- child coroutine
function coroutine_child()
print("Child Started.")
coroutine.yield("Child Yielded.")
print("Child Finished.")
return "Child Result."
end
function coroutine_parent()
print("Parent Started.")
local co_child = coroutine.create(coroutine_child)
local status, value = coroutine.resume(co_child)
print("Parent resumed child, status:", status, "yield:", value)
-- resume the child to finish its execution
status, result = coroutine.resume(co_child)
print("Parent resumed child again, status:", status, "result:", result)
print("Parent Finished.")
end
-- create a parent coroutine
co_parent = coroutine.create(coroutine_parent)
-- start the parent coroutine
coroutine.resume(co_parent)
Output
When we run the above program, we will get the following output−
Parent Started. Child Started. Parent resumed child, status: true yield: Child Yielded. Child Finished. Parent resumed child again, status: true result: Child Result. Parent Finished.
Explanation
coroutine_parent coroutine is creating a coroutine_child coroutine.
Next, parent coroutine is explicitly starting the child coroutine and a messge is printed.
Finally, parent again resume the child coroutine to finish its execution.
Example - Multilevel Nesting of Coroutine
We can nest coroutines to any level where parent creates a child and child creates a grandchild and so on. But such scenario needs careful consideration on communication between coroutines.
main.lua
-- child coroutine
function coroutine_grandchild()
print("Grandchild Started.")
coroutine.yield("Grandchild Yielded.")
print("Grandchild Finished.")
return "Grandchild Result."
end
-- child coroutine
function coroutine_child()
print("Child Started.")
local co_grandchild = coroutine.create(coroutine_grandchild)
local status, value = coroutine.resume(co_grandchild)
print("Child resumed grandchild, status:", status, "yield:", value)
-- resume the grandchild to finish its execution
coroutine.resume(co_grandchild)
coroutine.yield("Child Yielded.")
print("Child Finished.")
end
function coroutine_parent()
print("Parent Started.")
local co_child = coroutine.create(coroutine_child)
local status, value = coroutine.resume(co_child)
print("Parent resumed child, status:", status, "yield:", value)
-- resume the child to finish its execution
coroutine.resume(co_child)
print("Parent Finished.")
end
-- create a parent coroutine
co_parent = coroutine.create(coroutine_parent)
-- start the parent coroutine
coroutine.resume(co_parent)
Output
When we run the above program, we will get the following output−
Parent Started. Child Started. Grandchild Started. Child resumed grandchild, status: true yield: Grandchild Yielded. Grandchild Finished. Parent resumed child, status: true yield: Child Yielded. Child Finished. Parent Finished.
Explanation
parent coroutine is creating a child coroutine.
child coroutine is creating a grandchild coroutine.
We need to take care of chain of resume to propagate result.
Applications of Nesting Coroutines
Subtasks with larger Task − A parent coroutine can initiate multiple subtasks as child subtasks and meanwhile it can perform any asynchronous operation which might be a time taking process.
Modularize Complex Algorithm − We can break a big complex algorithm to small breakable parts as sub-coroutines while parent coroutine has to manage their executions as per algorithm's requirement.
Actors Implementation − We can implement actors as nested coroutines where an actor is to maintain its own state and interacts with other actors as coroutines.