解析关于Lua协同程序

移动开发 iOS
关于Lua协同程序的内容是本文要介绍的内容,主要是来学习lua中线程的使用方法,关于系统程序,本文有详解,具体内容一起来看详解。

关于Lua协同程序的内容是本文要介绍的内容,主要是来学习lua线程的使用方法,关于系统程序,本文有详解,具体内容一起来看详解。

1、什么是协同(coroutine)?

协同程序(coroutine)与线程比较类似:拥有独立的堆栈,独立的局部变量,独立的指令指针,但是和其他协同程序共享全局变量等很多信息。
  
线程协同程序的主要不同在于:在多处理器情况下,从概念上来讲多线程程序同时运行多个线程;而协同程序是通过协作来完成,在任一指定时刻只有一个协同程序在运行,并且这个正在运行的协同程序只有在明确的被要求挂起的时候才会被挂起。协作程序有点类似同步的多线程,在等待同一个线程锁的几个线程有点类似协同。

协同和顺序执行的区别?任一制定时刻只能运行一个协同程序,这个和顺序执行区别在哪?关键在于yield函数。如果顺序执行的时候进行耗费cpu时间或者一直等待某个资源的时候,程序将卡在这个地方不能前进。协同程序的出现就是可以使等待资源的线程让出资源,进行下一个协同程序的操作。yield可以在执行出错的时候挂起,下次恢复的时候再进行操作。

2、协同(coroutine)的几个状态

挂起态:创建一个协同程序时他开始的状态为挂起态,函数coroutine.yield可以使程序由运行态变为挂起状态

运行态:函数coroutine.resume可以使程序由挂起状态变为运行态

停止态:协同程序结束,进入停止态

3、coroutine.resume

resume可以给协同程序传参数,并将挂起态程序恢复为运行态

  1. coroutinecoroutine.co = coroutine.create(function (a,b,c)  
  2.     print("co", a, b, c)  
  3. end)  
  4. coroutine.resume(co, 1, 2, 3) --> co 1 2 3resume 

coroutine.resume直到线程结束或者遇到coroutine.yield时返回。

(1)coroutine.resume的参数:线程函数***次运行,参数作为线程函数参数;如果yield没有显式返回参数,则coroutine.resume的参数作为yield的额外参数返回。

(2)如果是挂起状态(一开始也是挂起状态),继续运行resume函数返回true;如果线程已经停止或者遇到其他错误,resume函数返回false及错误信息。

(3)线程结束则线程主函数的返回值作为coroutine.resume的附加返回值。

这点特性很微妙,可以看出coroutine.resume其实是个阻塞函数,阻塞等待协同程序完成或者yield退出。可以把协同程序当成一个等待对象,对象等待返回则coroutine.resume返回。在coroutine.resume调用的地方阻塞调用线程,这个特性要记住!

4、coroutine.yield

yield可以返回额外参数,或者挂起协同程序

  1. co = coroutine.create(function (a,b)  
  2.     coroutine.yield(a + b, a - b)  
  3. end)  
  4. print(coroutine.resume(co, 20, 10)) --> true 30 10  
  5.  
  6. co = coroutine.create (function ()  
  7.     print("co", coroutine.yield())  
  8. end)  
  9. coroutine.resume(co)  
  10. coroutine.resume(co, 4, 5) --> co 4 5 

使用函数yield可以使程序挂起并返回状态给resume,当我们激活被挂起的程序时,yield返回(这里的返回是说从阻塞状态返回)并继续程序的执行直到再次遇到yield或者程序结束

5、对称协同和不对称协同

对称协同:执行到挂起之间状态转换的函数是相同的

不对称协同:挂起一个正在执行的协同的函数与使一个被挂起的协同再次执行的函数是不同的(resum和yield)
 
6、消费者驱动的生产者-消费者模型

当消费者需要值时他唤起生产者生产值,生产者生产值后停止直到消费者再次请求。我们称这种设计为消费者驱动的设计。平常多见的生产者-消费者模型,是产品驱动的设计,生产者不断生产产品,消费者用临界区保护取产品消费

协同为解决这种问题提供了理想的方法,因为调用者与被调用者之间的resume-yield关系会不断颠倒。当一个协同调用yield时并不会进入一个新的函数,取而代之的是返回一个未决的resume的调用。相似的,调用resume时也不会开始一个新的函数而是返回yield的调用。这种性质正是我们所需要的,与使得send-receive协同工作的方式是一致的:receive唤醒生产者生产新值,send把产生的值送给消费者消费。

  1. function receive (prod)  
  2.     local status, value = coroutine.resume(prod)  
  3.     return value  
  4. end  
  5.  
  6. function send (x)  
  7.     coroutine.yield(x)  
  8. end  
  9.  
  10. function producer ()  
  11.     return coroutine.create(function ()  
  12.         while true do  
  13.             local x = io.read() -- produce new value  
  14.             send(x)  
  15.         end  
  16.  
  17.     end)  
  18. end  
  19.  
  20. function filter (prod)  
  21.     return coroutine.create(function ()  
  22.         local line = 1 
  23.         while true do  
  24.             local x = receive(prod) -- get new value  
  25.             x = string.format("%5d %s", line, x)  
  26.             send(x) -- send it to consumer  
  27.             lineline = line + 1  
  28.         end  
  29.     end)  
  30. end  
  31.  
  32. coroutine.resumefunction consumer (filter)  
  33.     while true do  
  34.         local x = receive(filter) -- get new value  
  35.         io.write(x, "\n") -- consume new value  
  36.     end  
  37. end  
  38. p = producer()  
  39. f = filter(p)  
  40. consumer(f) 

看完上面这个例子你可能很自然的想到UNIX的管道,协同是一种非抢占式的多线程。管道的方式下,每一个任务在独立的进程中运行,而协同方式下,每个任务运行在独立的协同代码中。管道在读(consumer)与写(producer)之间提供了一个缓冲,因此两者相关的的速度没有什么限制,在上下文管道中这是非常重要的,因为在进程间的切换代价是很高的。协同模式下,任务间的切换代价较小,与函数调用相当,因此读写可以很好的协同处理。

小结:解析关于Lua协同程序的内容介绍完了,希望通过本文的学习能对你有所帮助!

责任编辑:zhaolei 来源: 互联网
相关推荐

2013-12-12 17:27:51

Lua协同

2011-08-23 17:33:08

LuaMetatable

2011-08-31 16:47:07

Lua调试器

2011-08-23 13:15:37

LUAPackage

2011-08-23 16:48:41

Lua 5.1API 函数

2011-08-25 14:43:55

LUA对象序列化

2022-12-06 11:57:54

Lua参数

2011-08-24 16:59:59

LuaModule

2011-08-25 15:51:10

Lua脚本

2011-08-25 10:24:27

Lua

2011-08-23 15:34:56

Lua模式 匹配

2011-09-06 17:37:01

LUA应用

2011-08-25 14:03:32

UbuntuLUA安装

2011-08-24 14:33:14

LUA开发环境Decoda

2011-08-25 17:25:55

LUADelphi

2011-08-24 14:14:13

LUA环境 配置

2022-11-10 09:05:18

Lua配置文件

2011-08-23 11:25:40

LUA函数TOC

2011-08-25 15:21:02

Lua字符串

2013-12-12 16:30:20

Lua脚本语言
点赞
收藏

51CTO技术栈公众号