什么是协同(coroutine)?

Lua 协同程序(coroutine)与线程比较类似:拥有独立的堆栈,独立的局部变量,独立的指令指针,同时又与其它协同程序共享全局变量和其它大部分东西。

协同是非常强大的功能,但是用起来也很复杂。

线程和协同程序区别

线程与协同程序的主要区别在于,一个具有多个线程的程序可以同时运行几个线程,而协同程序却需要彼此协作的运行。

在任一指定时刻只有一个协同程序在运行,并且这个正在运行的协同程序只有在明确的被要求挂起的时候才会被挂起。

协同程序有点类似同步的多线程,在等待同一个线程锁的几个线程有点类似协同。

基本语法

方法 描述
coroutine.create() 创建coroutine,返回coroutine, 参数是一个函数,当和resume配合使用的时候就唤醒函数调用
coroutine.resume() 重启coroutine,和create配合使用
coroutine.yield() 挂起coroutine,将coroutine设置为挂起状态,这个和resume配合使用能有很多有用的效果
coroutine.status() 查看coroutine的状态
注:coroutine的状态有三种:dead,suspend,running,具体什么时候有这样的状态请参考下面的程序
coroutine.wrap() 创建coroutine,返回一个函数,一旦你调用这个函数,就进入coroutine,和create功能重复
coroutine.running() 返回正在跑的coroutine,一个coroutine就是一个线程,当使用running的时候,就是返回一个corouting的线程号

以下实例演示了以上各个方法的用法:

-- coroutine_test.lua 文件
co = coroutine.create(function(i)print(i);end
)coroutine.resume(co, 1)   -- 1
print(coroutine.status(co))  -- deadprint("----------")co = coroutine.wrap(function(i)print(i);end
)co(1)print("----------")co2 = coroutine.create(function()for i=1,10 doprint(i)if i == 3 thenprint(coroutine.status(co2))  --runningprint(coroutine.running()) --thread:XXXXXXendcoroutine.yield()endend
)coroutine.resume(co2) --1
coroutine.resume(co2) --2
coroutine.resume(co2) --3print(coroutine.status(co2))   -- suspended
print(coroutine.running())print("----------")

以上实例执行输出结果为:

1
dead
----------
1
----------
1
2
3
running
thread: 0x7fb801c05868    false
suspended
thread: 0x7fb801c04c88    true
----------

coroutine.running就可以看出来,coroutine在底层实现就是一个线程。

当create一个coroutine的时候就是在新线程中注册了一个事件。

当使用resume触发事件的时候,create的coroutine函数就被执行了,当遇到yield的时候就代表挂起当前线程,等候再次resume触发事件。

接下来我们分析一个更详细的实例:

function foo (a)print("foo 函数输出", a)return coroutine.yield(2 * a) -- 返回  2*a 的值
endco = coroutine.create(function (a , b)print("第一次协同程序执行输出", a, b) -- co-body 1 10local r = foo(a + 1)print("第二次协同程序执行输出", r)local r, s = coroutine.yield(a + b, a - b)  -- a,b的值为第一次调用协同程序时传入print("第三次协同程序执行输出", r, s)return b, "结束协同程序"                   -- b的值为第二次调用协同程序时传入
end)print("main", coroutine.resume(co, 1, 10)) -- true, 4
print("--分割线----")
print("main", coroutine.resume(co, "r")) -- true 11 -9
print("---分割线---")
print("main", coroutine.resume(co, "x", "y")) -- true 10 end
print("---分割线---")
print("main", coroutine.resume(co, "x", "y")) -- cannot resume dead coroutine
print("---分割线---")

以上实例执行输出结果为:

第一次协同程序执行输出    1    10
foo 函数输出    2
main    true    4
--分割线----
第二次协同程序执行输出    r
main    true    11    -9
---分割线---
第三次协同程序执行输出    x    y
main    true    10    结束协同程序
---分割线---
main    false    cannot resume dead coroutine
---分割线---

以上实例接下如下:

  • 调用resume,将协同程序唤醒,resume操作成功返回true,否则返回false;
  • 协同程序运行;
  • 运行到yield语句;
  • yield挂起协同程序,第一次resume返回;(注意:此处yield返回,参数是resume的参数)
  • 第二次resume,再次唤醒协同程序;(注意:此处resume的参数中,除了第一个参数,剩下的参数将作为yield的参数)
  • yield返回;
  • 协同程序继续运行;
  • 如果使用的协同程序继续运行完成后继续调用 resume方法则输出:cannot resume dead coroutine

resume和yield的配合强大之处在于,resume处于主程中,它将外部状态(数据)传入到协同程序内部;而yield则将内部的状态(数据)返回到主程中。


生产者-消费者问题

现在我就使用Lua的协同程序来完成生产者-消费者这一经典问题。

local newProductorfunction productor()local i = 0while true doi = i + 1send(i)     -- 将生产的物品发送给消费者end
endfunction consumer()while true dolocal i = receive()     -- 从生产者那里得到物品print(i)end
endfunction receive()local status, value = coroutine.resume(newProductor)return value
endfunction send(x)coroutine.yield(x)     -- x表示需要发送的值,值返回以后,就挂起该协同程序
end-- 启动程序
newProductor = coroutine.create(productor)
consumer()

以上实例执行输出结果为:

1
2
3
4
5
6
7
8
9
10
11
12
13
……============================================================================================

协同程序较为难理解,现在先收集下资料,将来用到时候再做详细学习

===============================================================================

lua的并发哲学 
实现并发:1、多线程(本质是共享内存数据、所以要同步多线程) 2、协程(本质是单线程、需要保证不阻塞)

协程的好处: 
1、不用线程调度所以可以更充分利用cpu、 
2、不处理线程同步减少bug、 
3、不会为了效率而故意打断逻辑上一致的代码块(所有有IO的地方后续的代码都要放在回调里), 
   虚拟机内部在IO函数上yield和resume,回调对用户是屏蔽的

缺点:一个协程阻塞会堵住所有的协程,所以要特殊处理IO

协程体系下的调度器:简单的顺序调度就可以有很高的吞吐率。

一篇不错的文章:

https://www.cnblogs.com/sifenkesi/p/3824321.html

Lua 协同程序(coroutine)相关推荐

  1. Lua中的协同程序 coroutine

    Lua中的协程和多线程很相似,每一个协程有自己的堆栈,自己的局部变量,可以通过yield-resume实现在协程间的切换.不同之处是:Lua协程是非抢占式的多线程,必须手动在不同的协程间切换,且同一时 ...

  2. lua运行外部程序_Lua 协同程序(coroutine)

    coroutine.creat方法只要建立了一个协程 ,那么这个协程的状态默认就是suspend.使用resume方法启动后,会变成running状态:遇到yield时将状态设为suspend:如果遇 ...

  3. Unity 中的协同程序

    今天咱就说说,协同程序coroutine.(这文章是在网吧敲的,没有unity,但是所有结论都被跑过,不管你信得过我还是信不过我,都要自己跑一下看看,同时欢迎纠错) 先说说啥是协程:协同程序是一个非常 ...

  4. unity控制程序等待_Unity 中的协同程序

    今天咱就说说,协同程序coroutine.(这文章是在网吧敲的,没有unity,但是所有结论都被跑过,不管你信得过我还是信不过我,都要自己跑一下看看,同时欢迎纠错) 先说说啥是协程:协同程序是一个非常 ...

  5. 【笨木头Lua专栏】基础补充07:协同程序初探

    哎,周五晚上我都还这么努力看书,真是好孩子.(小若:不想吐槽了) 其实我都准备玩游戏看电影去的了,但是这书就摆在桌子上,而且正对着我,就想着,扫两眼吧. 结果一扫就不对劲了,因为这内容有点绕,有点小混 ...

  6. (转载)【笨木头Lua专栏】基础补充07:协同程序初探

    哎,周五晚上我都还这么努力看书,真是好孩子.(小若:不想吐槽了) 其实我都准备玩游戏看电影去的了,但是这书就摆在桌子上,而且正对着我,就想着,扫两眼吧. 结果一扫就不对劲了,因为这内容有点绕,有点小混 ...

  7. 【笨木头Lua专栏】基础补充08:协同程序之resume-yield间的数据返回

    这次要介绍几个事实上非常easy,可是一定要小心的返回值规则. 笨木头花心贡献,哈?花心?不,是用心~ 转载请注明.原文地址: http://www.benmutou.com/archives/173 ...

  8. LUA 协程 Coroutine

    协程 Coroutine 协程(coroutine)并不是 Lua 独有的概念,如果让我用一句话概括,那么大概就是:一种能够在运行途中主动中断,并且能够从中断处恢复运行的特殊函数.(嗯,其实不是函数. ...

  9. 【unity】简要分析yield及协同程序的用法

    在学习unity3d的时候很容易看到下面这个例子: 1 void Start () {2 StartCoroutine(Destroy());3 }4 5 IEnumerator Destroy(){ ...

最新文章

  1. 最新完整版PHP配置文件翻译
  2. 机器学习笔记(五)——朴素贝叶斯分类
  3. java 路由_RabbitMQ入门:路由(Routing)
  4. 捕获系统异常崩溃的方法
  5. ssis导入xml_SSIS XML目标
  6. Csrf漏洞概述及其原理
  7. 上海羽毛球场预定app_生意火爆一席难求!普陀这家“羽毛球场”原来竟是……...
  8. python mro c3_Python的MRO以及C3线性化算法
  9. MVC---------ViewBag
  10. 防毒墙APT防护抗DDOS攻击
  11. 【拒绝一问就懵】之从Thread讲到Handle
  12. MySQL多表联查常用函数数据库设计规范
  13. 离职原因该怎么回答?
  14. 参数是list集合校验,使用@Vaild或者@Vaildated不起作用
  15. 软件测试的正向思维,反向思维
  16. 串口控制74HC164C语言,51单片机74HC164串口控制数码管显示
  17. 郭晶晶成功瘦身中环逛街 产后专心相夫教子
  18. RK3568平台开发系列讲解(视频篇)摄像头采集视频的相关配置
  19. 【调剂】其它计算机/软件调剂信息 21.3.16
  20. mysql索引的数据结构,各自优劣

热门文章

  1. 注解_JDK内置注解
  2. InvalidClassException异常_原理和解决方案
  3. 字节输入流一次读取多个字节
  4. 数据库-数据库的备份与恢复
  5. Topic交换器-搭建环境
  6. SpringBoot高级消息-RabbitMQ运行机制
  7. Java平台扩展机制#3:SLF4J怪招
  8. 同步与异步、并行与并发、阻塞与挂起
  9. cJSON_译(C中的超轻量级JSON解析器)
  10. 沃尔玛建立自家的人工智能网络,抗衡竞争对手亚马逊