BeWithYou

胡搞的技术博客

  1. 首页
  2. C/C++/Lua
  3. Lua学习笔记(三)

Lua学习笔记(三)


协程(coroutine):

协程与多线程的比较,有自己的堆栈、局部变量、指令指针等,但是协程本身与其他协程共享全局变量。主要不同在于,多处理器下,多线程可以真实的同时运行多个线程。而协程任意时刻只能有一个在真实运行,并且只有在明确要求被挂起时才会挂起。

协程有三个状态:挂起,运行,停止

co = coroutine.create(function() … end) -- 刚创建时为挂起态返回一个thread
coroutine.status(co) -- 返回suspended 检测协程的状态 为挂起
coroutine.resume(co) -- 运行
coroutine.status(co) -- 返回dead 已经结束了
协程使用yield来自行挂起,resume和yield可以相互交换数据。
co = coroutine.create(function(a,b)
    print(“fun",a,b)
    print("co",coroutine.yield(a+b,a*b,a-b))
return 1,2
end)
coroutine.resume(co,5,6) -- fun 5 6 返回true,11,30,-1
coroutine.resume(co,3,4) -- co 3 4 返回true,1,2

调用 coroutine.resume 函数执行一个协程。 第一次调用 coroutine.resume 时,第一个参数应传入 coroutine.create 返回的thread对象,然后协程从其主函数的第一行开始执行。 传递给 coroutine.resume 的其他参数将作为协程主函数的参数传入。 协程启动之后,将一直运行到它终止或 让出。

协程的运行可能被两种方式终止: 正常途径是主函数返回 (显式返回或运行完最后一条指令); 非正常途径是发生了一个未被捕获的错误。 对于正常结束, coroutine.resume 将返回 true, 并接上协程主函数的返回值。 当错误发生时, coroutine.resume 将返回 false 与错误消息。

通过调用 coroutine.yield 使协程暂停执行,让出执行权。 协程让出时,对应的最近 coroutine.resume 函数会立刻返回,即使该让出操作发生在内嵌函数调用中 (即不在主函数,但在主函数直接或间接调用的函数内部)。 在协程让出的情况下, coroutine.resume 也会返回 true, 并加上传给 coroutine.yield 的参数。 当下次重启同一个协程时, 协程会接着从让出点继续执行。 调用coroutine.yield 会返回任何传给 coroutine.resume 的第一个参数之外的其他参数。

与 coroutine.create 类似, coroutine.wrap 函数也会创建一个协程。 不同之处在于,它不返回协程本身,而是返回一个函数。 调用这个函数将启动该协程。 传递给该函数的任何参数均当作 coroutine.resume 的额外参数。 coroutine.wrap 返回 coroutine.resume 的所有返回值,除了第一个返回值(布尔型的错误码)。 和 coroutine.resume 不同,coroutine.wrap 不会捕获错误; 而是将任何错误都传播给调用者。


管道过滤器:

function receive (prod)
    local status, value = coroutine.resume(prod)
    return value
end
function send (x)
    coroutine.yield(x)
end
function producer ()
    return coroutine.create(function ()
        while true do
        local x = io.read()
        send(x)
        end 
    end)
end
-- produce new value
function filter (prod)
    return coroutine.create(function ()
        local line = 1
        while true do
        local x = receive(prod) -- get new value x = string.format("%5d %s", line, x) send(x) -- send it to consumer line = line + 1
        end 
    end)
end
function consumer (prod)
   while true do
   local x = receive(prod) -- get new value
   io.write(x, "\n") -- consume new value end
end

在生产者消费者中间加了一个filter用来添加行号。消费者主导,需要消费时resume filter,filter再resume producer获取商品,处理过后返回给consumer,自己yield。


迭代器协程:

打印一个数组的全排列

function permgen(a, n)
    if n == 0 then
        coroutine.yield(a)
    else
        a[n],a[i]= a[i],a[n] --交换第i个和最后一个
        permgen(a,n-1)
        a[n],a[i]=a[i],a[n] -- 换回来
    end
end
function perm(a)
    local n = #a
    local co = coroutine.create(function() permgen(a,n) end)
    return function() — iterator
        local code,res = coroutine.resume(co) — 到n=0的时候会yield 返回给resume 此时res就是排列的一个解
        return res — 最后一次resume以后返回nil
    end
end
-- perm返回一个迭代器函数,并不需要提供状态变量和控制变量。之后迭代器函数每次产生控制变量p,p即为一个排列。printResult打印p的所有元素
for p in perm({1,2,3,4}) do 
    printResult(p) 
end


非抢占式多线程:

多个协同程序执行任务时,可能任务中间很多时间花在不需要抢占的操作比如等待时,可以用统一调度的方式,在一个协程发现自己不需要抢占资源的时候可以主动yield出来,resume其他协程执行。这样保证不用把排队时间浪费在不必要的等待中。

回到顶部