Lua协程(coroutine)程序运行分析_Lua

这是一段分析 lua 协程(协同程序,coroutine)的代码,来自 Lua reference manual interface (略有修改):

复制代码 代码如下:

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

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

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

运行效果如下:

复制代码 代码如下:

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

这里一共调用了 4 次 resume ,让我们来看看它是怎么运行的。

第一次:

复制代码 代码如下:

print("main", coroutine.resume(co, 1, 10))

1.执行 print("co-body1", a, b) ,a 和 b 的值为 resume 提供,a=1, b=10 ;
2.计算 a+1=2 ,进入 foo(a) ,同时将刚才的计算结果通过 a 参数传递,执行 print("foo", a);
3.考虑 return coroutine.yield(2*a) ;
4.计算 2*a=4 ,碰到 yield,挂起 foo(a) 调用,将 4 返回给 resume 。注意,foo 的 return 还没有执行;
5.resume 执行成功,返回 true, 4 。

第二次:

复制代码 代码如下:

print("main", coroutine.resume(co, "r"))

1.从上一次挂起的 foo(a) 调用开始执行,接着执行没有完成的 return 调用;
2.因为 yield 返回 resume 的调用参数,此时 foo(a+1) 返回的值就是字符串 "r"。这里比较难理解。
因为大家可能会顺理成章地认为 local r 这个变量的值应该是 yield(2*a) 中的 2*a 的值。
需要注意的是, yield 的返回值 与 yield 参数的值 是不同的。
前者你可以将其保存在一个变量中,或者 return 它,或者不使用它(不保存 yield 的返回结果);后者则是 resume 的返回值。
3.执行 print("co-body2", r) ,r 的值为 "r" ;
4.考虑 local r, s = coroutine.yield(a+b, a-b) ;
5.计算 a+b=11, a-b=-9 ,碰到 yield ,挂起 co 的调用,将 11 和 9 返回给 resume 。注意,此时 local r, s 的赋值还没有开始。
这里不太好理解的是,为什么 a 的值不是 "r" ?因为 "r" 已经被上面的 yield 的返回值给消费掉了。
6.resume 执行成功,返回 true, 11, -9 。

第三次:

复制代码 代码如下:

print("main", coroutine.resume(co, "x", "y"))

1.从上一次 yield 的地方开始执行,接着执行没有完成的 local r, s = 赋值。上面提到, yield 会返回 resume 的调用参数,因此 r 和 s 的值就是 "x" 和 "y" ;
2.执行 print("co-body3", r, s) 进行打印;
3.考虑 return b, "end" ;
4.b 的值一直都是 10 没有变,这里直接返回了,同时返回的还有 "end" 这个字符串;
5.由于协程函数返回的时候,它的所有返回值都作为 resume 的返回值返回。因此这里的 resume 执行成功,返回 10, "end" 。

第四次:

复制代码 代码如下:

print("main", coroutine.resume(co, "x", "y"))

由于 co 函数已经返回,它处于 dead 状态,不能 resume ,因此第 4 次 resume 失败。

时间: 2024-08-02 00:41:56

Lua协程(coroutine)程序运行分析_Lua的相关文章

LUA 协程 Coroutine

协程 Coroutine 协程(coroutine)并不是 Lua 独有的概念,如果让我用一句话概括,那么大概就是:一种能够在运行途中主动中断,并且能够从中断处恢复运行的特殊函数.(嗯,其实不是函数.) 举个最原始的例子: 下面给出一个最简单的 Lua 中 coroutine 的用法演示: function greet() print "hello world" end co = coroutine.create(greet) -- 创建 coroutine print(corouti

【转】【UNITY3D 游戏开发之六】UNITY 协程COROUTINE与INVOKE

本站文章均为 李华明Himi 原创,转载务必在明显处注明:  转载自[黑米GameDev街区] 原文链接: http://www.himigame.com/unity3d-game/1610.html 这里Himi强调一点:Unity里面的协程并不是线程,协程是在unity主线程中运行的,每一帧中处理一次,而并不与主线程并行.这就意味着在协程之间并不存在着所谓线程间的同步和互斥问题,不会出现死锁.一般来说,访问同一个值也都是很安全的,用协程可以处理绝大多数的小问题,而且不用考虑复杂的线程间同步,

Lua的协程(coroutine)简介_Lua

协程和多线程下的线程类似:有自己的堆栈,自己的局部变量,有自己的指令指针,但是和其他协程程序共享全局变量等信息.线程和协程的主要不同在于:多处理器的情况下,概念上来说多线程是同时运行多个线程,而协程是通过协作来完成,任何时刻只有一个协程程序在运行.并且这个在运行的协程只有明确被要求挂起时才会被挂起 你可以使用coroutine.create来创建协程: 复制代码 代码如下: co = coroutine.create(function ()      print("hi") end)

Lua中的协同程序详解_Lua

前言 协同程序与线程差不多,也就是一条执行序列,拥有自己独立的栈.局部变量和指令指针,同时又与其它协同程序共享全局变量和其它大部分东西.从概念上讲,线程与协同程序的主要区别在于,一个具有多个线程的程序可以同时运行几个线程,而协同程序却需要彼此协作的运行.就是说,一个具有多个协同程序的程序在任意时刻只能运行一个协同程序,并且正在运行的协同程序只会在其显式地要求挂起时,它的执行才会暂停. 协同程序基础 Lua将所有关于协同程序的函数放置在一个名为"coroutine"的table中.函数c

使用Lua来扩展C++程序的方法_Lua

 介绍 如果用户能够通过一些脚本语言来修改应用本身的行为,那么许多应用可以变得更适合用户使用.一些商业应用就提供了此类便利.例如 Microsoft Office 的 VBA 脚本编程或在视频游戏 World of Warcraft 中使用 Lua .脚本语言把应用作为一个平台提供一系列终端用户可以获得并操控的服务. 做为嵌入到程序中的语言,我们有很多可用的选择:开源和不开源的脚本引擎,或者可以从头开始创建一个.现在,最为熟知的脚本语言是JavaScript,Lua和Python,还有很多其它的

Lua协同程序(COROUTINE)运行步骤分解_Lua

这是一段分析 lua 协程(协同程序,coroutine)的代码,来自 Lua reference manual interface (略有修改): 复制代码 代码如下: function foo (a)     print("foo", a)     return coroutine.yield(2*a) end co = coroutine.create(function (a,b)    print("co-body1", a, b)    local r =

Lua中的协同程序 coroutine(转)

Lua中的协程和多线程很相似,每一个协程有自己的堆栈,自己的局部变量,可以通过yield-resume实现在协程间的切换.不同之处是:Lua协程是非抢占式的多线程,必须手动在不同的协程间切换,且同一时刻只能有一个协程在运行.并且Lua中的协程无法在外部将其停止,而且有可能导致程序阻塞.   协同程序(Coroutine): 三个状态:suspended(挂起,协同刚创建完成时或者yield之后).running(运行).dead(函数走完后的状态,这时候不能再重新resume). corouti

ucontext-人人都可以实现的简单协程库

1.干货写在前面 协程是一种用户态的轻量级线程.本篇主要研究协程的C/C++的实现. 首先我们可以看看有哪些语言已经具备协程语义: 比较重量级的有C#.erlang.golang* 轻量级有python.lua.javascript.ruby 还有函数式的scala.scheme等. c/c++不直接支持协程语义,但有不少开源的协程库,如: Protothreads:一个"蝇量级" C 语言协程库 libco:来自腾讯的开源协程库libco介绍,官网 coroutine:云风的一个C语

[译]C语言协程

C语言协程 by Simon Tatham 原文链接:http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html 引言 为大型程序设计一个良好的结构通常是一件困难的事情.其中一个经常出现的问题是:如果你有一段代码产生数据,另一段代码消费数据,那么谁应该作为调用者,谁应该作为被调用者? 下面是一段很简单的Run-Length(游程编码)解压缩代码(Decompressor): /* Decompression code */ while