Lua Coroutine详解
协同程序与线程差不多,也就是一条执行序列,拥有自己独立的栈,局部变量和指令指针,同时又与其它协同程序共享全局变量和其它大部分东西。线程与协同程序的主要区别在于,一个具有多线程的程序可以同时运行几个线程,而协同程序却需要彼此协作地运行。就是说,一个具有多个协同程序的程序在任何时刻只能运行一个协同程序,并且正在运行的协同程序只会在其显示地挂起时,它的执行才会暂停。
一、 lua协程函数概览
| 方法 | 描述 |
|---|---|
| coroutine.create() | 创建coroutine,返回coroutine, 参数是一个函数,当和resume配合使用的时候就唤醒函数调用 |
| coroutine.resume() | 重启coroutine,和create配合使用 |
| coroutine.yield() | 挂起coroutine,将coroutine设置为挂起状态,这个和resume配合使用能有很多有用的效果 |
| coroutine.status() | 查看coroutine的状态.注:coroutine的状态有四种:dead,suspend,running,normal |
| coroutine.wrap() | 创建coroutine,返回一个函数,一旦你调用这个函数,就进入coroutine,和create功能重复 |
| coroutine.running() | 返回正在跑的coroutine,一个coroutine就是一个线程,当使用running的时候,就是返回一个corouting的线程号 |
二、 函数详解
1. coroutine.create(f)
创建一个主体函数为 f 的新协程。 f 必须是一个 Lua 的函数。 返回这个新协程,它是一个类型为 "thread" 的对象。不会启动该协程。
local co = coroutine.create(
function()
print("in coroutine")
return "coroutine return"
end)
print(co)
print(coroutine.resume(co))
Output:
thread: 0039B808
in coroutine
true coroutine return
2. coroutine.resume(co, [, val1, ...])
开始或继续协程co的运行。当第一次执行一个协程时,他会从主函数处开始运行。val1,...这些值会以参数形式传入主体函数。 如果该协程被挂起,resume 会重新启动它; val1, ... 这些参数会作为挂起点的返回值。如果协程运行起来没有错误, resume 返回 true 加上传给 yield 的所有值 (当协程挂起), 或是主体函数的所有返回值(当协程中止)。
local co = coroutine.create(
function (input)
print("input : "..input)
local param1, param2 = coroutine.yield("yield")
print("param1 is : "..param1)
print("param2 is : "..param2)
-- return 也会将结果返回给 resume
return "return"
end)
--第一次执行,将参数传给input
print(coroutine.resume(co, "function input"))
print("this is main chunk")
--第二次执行,将参数作为yield的返回值,传给param1 param2
print(coroutine.resume(co, "param1", "param2"))
Output:
input : function input
true yield
this is main chunk
param1 is : param1
param2 is : param2
true return
coroutine.resume 是在保护模式中运行,如果有任何错误发生, Lua 是不会显示任何错误, 而是 返回 false 加错误消息。同时,这个协程的状态会变成dead。
local co = coroutine.create(
function()
print("error test")
--调用一个空值得属性
coroutine.yield(a.a)
end)
-- 返回结果为 false 以及错误信息
print(coroutine.resume(co))
-- 协程的状态变为 dead
print(coroutine.status(co))
Output:
error test
false K:\lua\coroutine.lua:49: attempt to index global 'a' (a nil value)
dead
3. coroutine.yield(...)
挂起正在调用的协程的执行。 传递给 yield 的参数都会转为 resume 的额外返回值。
local co = coroutine.create(
function ()
coroutine.yield("yield1" ,"yield2")
end)
print(coroutine.resume(co))
Output:
true yield1 yield2
4. coroutine.status(co)
以字符串形式返回协程 co 的状态:
- 当协程正在运行(它就是调用 status 的那个) ,返回 "running";
- 如果协程调用 yield 挂起或是还没有开始运行,返回 "suspended";
- 如果协程是活动的,都并不在运行(即它正在延续其它协程),返回 "normal";
- 如果协程运行完主体函数或因错误停止,返回 "dead"。
local co
local co2 = coroutine.create(function() print("3."..coroutine.status(co)) end)
co = coroutine.create(
function ()
print("2."..coroutine.status(co))
coroutine.resume(co2)
coroutine.yield()
end)
print("1."..coroutine.status(co))
coroutine.resume(co)
print("4."..coroutine.status(co))
coroutine.resume(co)
print("5."..coroutine.status(co))
Output:
1.suspended
2.running
3.normal
4.suspended
5.dead
5. coroutine.running()
返回当前的协程,如果实在主线程,则返回nil
local co = coroutine.create(
function ()
print(coroutine.running())
end)
print(coroutine.running())
coroutine.resume(co)
print(co)
Output:
nil
thread: 003FC9A0
thread: 003FC9A0
** Lua 5.3 有变动 **
6. coroutine.wrap(f)
创建一个主体函数为 f 的新协程。 f 必须是一个 Lua 的函数。 返回一个函数, 每次调用该函数都会延续该协程。 传给这个函数的参数都会作为 resume 的额外参数。 和 resume 返回相同的值, 只是没有第一个布尔量。
local wrap = coroutine.wrap(
function (input)
print("input : "..input)
local param1, param2 = coroutine.yield("yield")
print("param1 is : "..param1)
print("param2 is : "..param2)
-- return 也会将结果返回给 resume
return "return"
end)
--第一次执行,将参数传给input
print(wrap("function input"))
print("this is main chunk")
--第二次执行,将参数作为yield的返回值,传给param1 param2
print(wrap("param1", "param2"))
Output:
input : function input
yield
this is main chunk
param1 is : param1
param2 is : param2
return
coroutine.wrap不是保护模式运行,如果发生任何错误,抛出这个错误。
local wrap = coroutine.wrap(
function()
print("error test")
--调用一个空值得属性
coroutine.yield(a.a)
end)
-- 返回结果为 false 以及错误信息
print(coroutine.resume(co))
这段代码在运行时,会抛出异常。
三、实例
摘自 《Lua 程序设计(第二版)》
-- 使用协程实现生产者消费者
function receive()
local status, value = coroutine.resume(producer)
return value
end
function send(x)
coroutine.yield(x)
end
producer = coroutine.create(
function()
while true do
local x = io.read()
send(x)
end
end)
function consumer ()
while true do
local x = receive()
io.write(x, "\n")
end
end
consumer();
Lua Coroutine详解的更多相关文章
- cocos2dx-3.x 导出自定义类到 lua 过程详解
转载请注明出处:http://www.cnblogs.com/Ray1024 一.简介 最近正在学习cocos2d中的lua游戏开发,因为lua开发的热更新特性,大家开发游戏好像都会优先选择lua作为 ...
- Unity3D中的Coroutine详解
Unity中的coroutine是通过yield expression;来实现的.官方脚本中到处会看到这样的代码. 疑问: yield是什么? Coroutine是什么? unity的coroutin ...
- 【精选】Nginx模块Lua-Nginx-Module学习笔记(二)Lua指令详解(Directives)
源码地址:https://github.com/Tinywan/Lua-Nginx-Redis Nginx与Lua编写脚本的基本构建块是指令. 指令用于指定何时运行用户Lua代码以及如何使用结果. 下 ...
- Nginx模块Lua-Nginx-Module学习笔记(二)Lua指令详解(Directives)
源码地址:https://github.com/Tinywan/Lua-Nginx-Redis Nginx与Lua编写脚本的基本构建块是指令. 指令用于指定何时运行用户Lua代码以及如何使用结果. 下 ...
- 【Unity3D/C#】Unity3D中的Coroutine详解
Unity中的coroutine是通过yield expression;来实现的.官方脚本中到处会看到这样的代码. 疑问: yield是什么? Coroutine是什么? unity的coroutin ...
- 游戏算法中lua脚本详解
此外,函数本身也是一个变量,比如: dp@dp:~ % cat test.lua local mylen={} mylen.len3=function (x,y,z) return math.sqrt ...
- lua元表详解
元表的作用 元表是用来定义对table或userdata操作方式的表 举个例子 local t1 = {1} local t2 = {2} local t3 = t1 + t2 我们直接对两个tabl ...
- Tornado中gen.coroutine详解
1.gen.coroutine的作用 自动执行生成器 2.Future对象 在介绍异步使用之前,先了解一下Future对象的作用. Future简单可以理解为一个占位符,将来会执行的对象,类似java ...
- Unity Coroutine详解(二)
• 介绍• Part 1. 同步等待• Part 2. 异步协程• Part 3. 同步协程• Part 4. 并行协程 1.介绍 ...
随机推荐
- 【图像处理】【SEED-VPM】1.板子基本操作流程
>>>>>>>>>>>>>>>>>>>>>>>>> ...
- C++小项目:directx11图形程序(九):总结
整篇文章中对于directx11的知识的介绍并不多,我也不知道怎么介绍,也应该说对于directx,它有它自己的部分,比如设备(device),设备上下文(devicecontext),顶点缓存,索引 ...
- Linux学习 :SPI通讯协议
SPI接口的全称是"Serial Peripheral Interface",意为串行外围接口,是Motorola首先在其MC68HCXX系列处理器上定义的.SPI接口主要应用在E ...
- C# dll加载,抽象方法的使用
抽象类! dll的使用 /// <summary> /// 返回类型--插件 /// </summary> /// <param name="baseName& ...
- HTML代码简写法:Emmet和Haml
http://www.ruanyifeng.com/blog/2013/06/emmet_and_haml.html?bsh_bid=657901854 HTML代码简写法:Emmet和Haml ...
- Ibatis动态拼装sql,常用标签总结及举栗子。
今天得到项目经理一项任务,就是拼装sql,第一次见到,不是太懂,赶紧回来睡一觉再说,由于这次的项目orm使用的是ibatis框架,所以需要使用动态拼装sql,或者是ognl语言,这门语言不是专属于ib ...
- EXCEL里面的数字显示为文本 不用科学计数法显示
1. 在输入这一串数字前加撇号“'”(英文状态下的单引号)即可.2. 先将这一列设置为“文本”格式,然后直接输入这一串数字即可. 已经输入好了数字,那估计你这些数字的后三位都已经全变成“0”了,用 ...
- jQuery原生框架-----------------属性操作
// 添加一个处理兼容获取样式的静态方法jQuery.getStyle = function( dom, styleName ) { // dom不是dom,styleName不是字符串,直接打走 i ...
- #define用法解析
#define Add(a,b) a+b; 在一般使用的时候是没有问题的,但是如果遇到如: c * Add(a,b) * d 的时候就会出现问题,代数式的本意是a+b然后去和c,d相乘,但是因为使用了 ...
- Ubuntu 14.10 创建虚拟网卡实现桥接网络
目标需求:在Ubuntu主机创建一张虚拟网卡,使得搭建在VirtualBox中的其他主机能借助虚拟网卡构建的局域网进行相互间的通讯 步骤一:准备工具包 安装 uml-utilities 以及 brid ...