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();


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM