lua学习之协同程序

转载:http://www.cnblogs.com/sifenkesi/p/3824321.html  

  Lua中的协程和多线程很相似,每一个协程有自己的堆栈,自己的局部变量,可以通过yield-resume实现在协程间的切换。不同之处是:Lua协程是非抢占式的多线程,必须手动在不同的协程间切换,且同一时刻只能有一个协程在运行。并且Lua中的协程无法在外部将其停止,而且有可能导致程序阻塞。

协同程序(Coroutine):

  三个状态:suspended(挂起,协同刚创建完成时或者yield之后)、running(运行)、dead(函数走完后的状态,这时候不能再重新resume)。

  coroutine.create(arg):根据一个函数创建一个协同程序,参数为一个函数

  coroutine.resume(co):使协同从挂起变为运行(1)激活coroutine,也就是让协程函数开始运行;(2)唤醒yield,使挂起的协同接着上次的地方继续运行。该函数可以传入参数

  coroutine.status(co):查看协同状态

  coroutine.yield():使正在运行的协同挂起,可以传入参数

  resume函数的两种用途虽然都是使协同挂起,但还是有些许差异的,看下面这个例子:

coroutineFunc = function (a, b)
    for i = 1, 10 do
        print(i, a, b)
        coroutine.yield()
    end
end

co2 = coroutine.create(coroutineFunc)        --创建协同程序co2
coroutine.resume(co2, 100, 200)                -- 1 100 200 开启协同,传入参数用于初始化
coroutine.resume(co2)                        -- 2 100 200
coroutine.resume(co2, 500, 600)                -- 3 100 200 继续协同,传入参数无效

co3 = coroutine.create(coroutineFunc)        --创建协同程序co3
coroutine.resume(co3, 300, 400)                -- 1 300 400 开启协同,传入参数用于初始化
coroutine.resume(co3)                        -- 2 300 400
coroutine.resume(co3)                        -- 3 300 400 

  Lua中协同的强大能力,还在于通过resume-yield来交换数据:

  (1)resume把参数传给程序(相当于函数的参数调用);

  (2)数据由yield传递给resume;

  (3)resume的参数传递给yield;

  (4)协同代码结束时的返回值,也会传给resume

  协同中的参数传递形势很灵活,一定要注意区分,在启动coroutine的时候,resume的参数是传给主程序的;在唤醒yield的时候,参数是传递给yield的。看下面这个例子:

co = coroutine.create(function (a, b) print("co", a, b, coroutine.yield()) end)
coroutine.resume(co, 1, 2)        --没输出结果,注意两个数字参数是传递给函数的
coroutine.resume(co, 3, 4, 5)        --co 1 2 3 4 5,这里的两个数字参数由resume传递给yield 

  Lua的协同称为不对称协同(asymmetric coroutines),指“挂起一个正在执行的协同函数”与“使一个被挂起的协同再次执行的函数”是不同的,有些语言提供对称协同(symmetric coroutines),即使用同一个函数负责“执行与挂起间的状态切换”。

  注意:resume运行在保护模式下,因此,如果协同程序内部存在错误,Lua并不会抛出错误,而是将错误返回给resume函数。

  以下是我个人的一点理解:

  (1)resume可以理解为函数调用,并且可以传入参数,激活协同时,参数是传给程序的,唤醒yield时,参数是传递给yield的;

  (2)yield就相当于是一个特殊的return语句,只是它只是暂时性的返回(挂起),并且yield可以像return一样带有返回参数,这些参数是传递给resume的。

为了理解上面两句话的含义,我们来看一下如何利用Coroutine来解决生产者——消费者问题的简单实现:

produceFunc = function()
    while true do
        local value = io.read()
        print("produce: ", value)
        coroutine.yield(value)        --返回生产的值
    end
end

consumer = function(p)
    while true do
        local status, value = coroutine.resume(p);        --唤醒生产者进行生产
        print("consume: ", value)
    end
end

--消费者驱动的设计,也就是消费者需要产品时找生产者请求,生产者完成生产后提供给消费者
producer = coroutine.create(produceFunc)
consumer(producer)

这是一种消费者驱动的设计,我们可以看到resume操作的结果是等待一个yield的返回,这很像普通的函数调用,有木有。我们还可以在生产消费环节之间加入一个中间处理的环节(过滤器):

produceFunc = function()
    while true do
        local value = io.read()
        print("produce: ", value)
        coroutine.yield(value)        --返回生产的值
    end
end

filteFunc = function(p)
    while true do
        local status, value = coroutine.resume(p);
        value = value *100            --放大一百倍
        coroutine.yield(value)
    end
end

consumer = function(f, p)
    while true do
        local status, value = coroutine.resume(f, p);        --唤醒生产者进行生产
        print("consume: ", value)
    end
end

--消费者驱动的设计,也就是消费者需要产品时找生产者请求,生产者完成生产后提供给消费者
producer = coroutine.create(produceFunc)
filter = coroutine.create(filteFunc)
consumer(filter, producer)

  可以看到,我们在中间过滤器中将生产出的值放大了一百倍。

  通过这个例子应该很容易理解coroutine中如何利用resume-yield调用来进行值传递了,他们像“调用函数——返回值”一样的工作,也就是说resume像函数调用一样使用,yield像return语句一样使用。coroutine的灵活性也体现在这种通过resume-yield的值传递上。

另一篇讲得比较清楚的博文: http://blog.chinaunix.net/uid-28295089-id-4150141.html

时间: 2024-10-14 14:45:06

lua学习之协同程序的相关文章

Lua chapter 8 协同程序

1.协同程序,一个具有多个协同程序的程序在任意时刻,只能运行一个协同程序, 只有正在运行的协同程序被挂起时,它的执行才会暂停. 创建 co = coroutine.create(匿名函数);   -- 匿名函数就是线程要执行的东东 状态 coroutine.status(co); 唤醒 coroutine.resume(co); 挂起 coroutine.yield(); 2.yield-resume 数据交换 function f(a,b) coroutine.yield(a*10,b*10)

Lua中的协同程序 coroutine

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

Lua中的协同程序 coroutine(转)

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

Lua中的协同程序

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

lua程序设计之协同程序

本文的内容主要来自于<lua程序设计>一书,部分内容来自网络 一个具有多个协同程序的程序在任意时刻只能运行一个协同程序,并且正在运行的协同程序只会在其显式地要求挂起时,它的执行才会暂停. 一 协同程序基础 -协同程序的函数放在"coroutine"的table中 -状态status -suspended 初始状态(创建时) -running -    dead -normal:当协程A唤醒协程B,A就处于normal状态 -coroutine函数 -coroutine.cr

Lua学习笔记之协同程序

1.  协同程序与多线程情况下的线程比较类似,有自己的堆栈.自己的局部变量,有自己的指令指针,但是和其他协同程序共享全局变量等很多信息.线程和协同程序的主要不同在于:在多核处理器情况下,多线程程序同时运行多个线程,而协同程序是通过协作来完成,在任意指定时刻只有一个协同程序在运行,并且这个正在运行的协同程序只有在明确的被要求挂起的时候才被挂起. 2.  协同的基础 Lua通过table提供了所有的协同函数,create函数创建一个新的协同程序,create只有一个参数,协同程序将要运行的代码封装而

《Lua程序设计》9.3 以协同程序实现迭代器 学习笔记

例:编写一个迭代器,使其可以遍历某个数组的所有排列组合形式.代码如下: function permgen(a, n) n = n or #a -- 默认n为a的大小 if n <= 1 then -- 还需要改变吗? printResult(a) else for i=1,n do -- 将第一个元素放到数组末尾 a[n], a[i] = a[i], a[n] -- 生成其余元素的排列 permgen(a, n-1) -- 恢复第i个元素 a[n], a[i] = a[i], a[n] end

Lua 学习笔记(九)协同程序(线程thread)

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

《Lua程序设计》9.1 协同程序基础 学习笔记

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