第一版是针对 Lua 5.0 编写的。尽管在很大程度上仍然适用于后续版本,但还是有一些差异。
第四版针对 Lua 5.3,可在 亚马逊 和其他书店购买。
购买本书,您还可以帮助 支持 Lua 项目。
用 Lua 编程 | ||
第一部分。语言 第 9 章。协程 |
Lua 将其所有协程函数打包在 coroutine
表中。create
函数创建新的协程。它有一个参数,即包含协程将运行的代码的函数。它返回类型为 thread
的值,该值表示新协程。通常,create
的参数是匿名函数,如下所示
co = coroutine.create(function () print("hi") end) print(co) --> thread: 0x8071d98
协程可以处于三种不同的状态之一:挂起、运行和死亡。当我们创建协程时,它从挂起状态开始。这意味着当我们创建协程时,它不会自动运行其主体。我们可以使用 status
函数检查协程的状态
print(coroutine.status(co)) --> suspended函数
coroutine.resume
(re)启动协程的执行,将其状态从挂起更改为运行
coroutine.resume(co) --> hi在此示例中,协程主体仅打印
"hi"
并终止,使协程处于死亡状态,无法从中返回
print(coroutine.status(co)) --> dead
到目前为止,协程看起来只不过是一种复杂的方法来调用函数。协程的真正强大之处在于 yield
函数,它允许正在运行的协程挂起其执行,以便以后可以恢复其执行。让我们看一个简单的示例
co = coroutine.create(function () for i=1,10 do print("co", i) coroutine.yield() end end)现在,当我们恢复此协程时,它将开始执行并运行到第一个
yield
coroutine.resume(co) --> co 1如果我们检查其状态,我们可以看到协程已挂起,因此可以再次恢复
print(coroutine.status(co)) --> suspended从协程的角度来看,当它被挂起时发生的所有活动都发生在其对
yield
的调用中。当我们恢复协程时,对 yield
的调用最终返回,协程继续执行,直到下一个 yield 或结束
coroutine.resume(co) --> co 2 coroutine.resume(co) --> co 3 ... coroutine.resume(co) --> co 10 coroutine.resume(co) -- prints nothing在最后一次调用
resume
时,协程主体完成了循环然后返回,因此协程现在已死亡。如果我们尝试再次恢复它,resume
将返回 false 加上错误消息
print(coroutine.resume(co)) --> false cannot resume dead coroutine请注意,
resume
在受保护模式下运行。因此,如果协程内部有任何错误,Lua 不会显示错误消息,而是会将其返回给 resume
调用。
Lua 中的一个有用功能是 resume-yield 对可以相互交换数据。第一个 resume
没有对应的 yield
等待它,它将它的额外参数作为协程主函数的参数传递
co = coroutine.create(function (a,b,c) print("co", a,b,c) end) coroutine.resume(co, 1, 2, 3) --> co 1 2 3调用
resume
后返回,在 true 表示没有错误后,返回传递给对应的 yield
的任何参数
co = coroutine.create(function (a,b) coroutine.yield(a + b, a - b) end) print(coroutine.resume(co, 20, 10)) --> true 30 10对称地,
yield
返回传递给对应的 resume
的任何额外参数
co = coroutine.create (function () print("co", coroutine.yield()) end) coroutine.resume(co) coroutine.resume(co, 4, 5) --> co 4 5最后,当协程结束时,它的主函数返回的任何值都将转到对应的
resume
co = coroutine.create(function () return 6, 7 end) print(coroutine.resume(co)) --> true 6 7
我们很少在同一个协程中使用所有这些功能,但它们都有各自的用途。
对于那些已经了解一些协程的人来说,在我们继续之前澄清一些概念非常重要。Lua 提供了我称之为非对称协程的东西。这意味着它有一个函数来暂停协程的执行,还有一个不同的函数来恢复已暂停的协程。一些其他语言提供对称协程,其中只有一个函数可以将控制权从任何协程转移到另一个协程。
有些人称非对称协程为半协程(因为它们不对称,所以它们并不是真正的协程)。然而,其他人使用相同的术语半协程来表示协程的受限实现,其中协程只能在其不在任何辅助函数中时暂停其执行,即当其控制堆栈中没有挂起调用时。换句话说,只有此类半协程的主体才能产生。Python 中的生成器是半协程这种含义的一个例子。
与对称协程和非对称协程之间的差异不同,协程和生成器(如 Python 中所示)之间的差异是深刻的;生成器根本不够强大,无法实现我们可以用真正的协程编写的几个有趣的构造。Lua 提供真正的非对称协程。那些喜欢对称协程的人可以在 Lua 的非对称功能之上实现它们。这是一项简单的任务。(基本上,每个传输都执行一个 yield,然后执行一个 resume。)
版权所有 © 2003–2004 Roberto Ierusalimschy。保留所有权利。 |