同步發表於個人網站
Lua提供coroutine
的函式庫,使其有能力編寫不同模式的程式。
你可以透過coroutine.create()
建立一個thread
。
t1 = coroutine.create(function() print("Hello, World") end)
print(type(t1)) -- Output: thread
Lua並不是多執行緒的,其thread
是輕量的。儘管Lua本身沒有異步(async)的寫法,但可以創造出異步的寫法。相對而言,值執行順序是明確許多的。
可以透過coroutine.resume()
去觸發一個thread
的執行:
coroutine.resume(t1) -- Output: Hello, World
可以對一個剛建立好的thread
傳入參數。
function hello(name)
while true do
coroutine.yield("Hello, " .. name)
end
end
t1 = coroutine.create(hello)
print(coroutine.status(t1)) -- suspended
print(coroutine.resume(t1, "Bob")) -- Output: Hello, Bob
print(coroutine.status(t1)) -- suspended
print(coroutine.resume(t1, "World")) -- Output: Hello, Bob
可以透過coroutine.clsoe()
關閉thread
:
coroutine.close(t1) --> true
coroutine.status(t1) --> dead
※ Node: 執行完畢的t1
原本就處於dead
,而無法再次執行。
可以透過coroutine.yield()
可以保留執行狀態,並返回:
function genNumber(n)
n = n or 0
while n < 100 do
n = n + 1
coroutine.yield(n)
end
end
t1 = coroutine.create(genNumber)
for i=1,3,1 do
print(coroutine.resume(t1))
end
true 1
true 2
true 3
coroutine.yield()
也可以用於取得而外傳入參數,讓整個更靈活一些。
function genNumber(n)
n = n or 0
while n < 100 do
n = coroutine.yield() or n
n = n + 1
coroutine.yield(n)
end
return 'finish'
end
t1 = coroutine.create(genNumber)
for i=1,3,1 do
coroutine.resume(t1)
print(coroutine.resume(t1)) --> 1, 2, 3
end
coroutine.resume(t1)
print(coroutine.resume(t1,96)) -- 97
for i=1,3,1 do
coroutine.resume(t1)
print(coroutine.resume(t1)) --> 98, 99, 100
end
print(coroutine.resume(t1)) --> finish
print(coroutine.status(t1)) --> dead
true 1
true 2
true 3
true 97
true 98
true 99
true 100
true finish
dead
thread.wrap()
可以將thread
包裹成函式function
t1 = coroutine.wrap(genNumber)
print(type(t1)) --> function
for i=1,3,1 do
t1()
print(t1()) --> 1, 2, 3
end
t1()
print(t1(96)) -- 97
for i=1,3,1 do
t1()
print(t1()) --> 98, 99, 100
end
print(t1()) --> finish
當有客人(消費者)來的時候,主廚(生產者)就做餐給客人。
function producer()
local i = 10
while true do
coroutine.yield(i)
i = i + 10
end
end
function consumer(p)
for i=1,10,1 do
local get = p()
coroutine.yield(i, get)
end
end
p = coroutine.wrap(producer)
c = coroutine.wrap(consumer)
-- start consumer, pass producer ---
i, p = c(p)
print("consume: i:", i, ", get:", p)
-- run until no consume --
while i do
print("consume: i:", i, ", get:", p)
i, p = c()
end
現在我們嘗試讓同一個生產者,服務兩個消費者:
p = coroutine.wrap(producer)
c1 = coroutine.wrap(consumer) -- consumer 1
c2 = coroutine.wrap(consumer) -- consumer 2
----- start consumer 1 with p ------
i1, get1 = c1(p)
print("consumer_1: i:", i1, "get:", get1)
----- start consumer 2 with p ------
i2, get2 = c2(p)
print("consumer_2: i:", i2, "get:", get2)
------ loop -------
while i1 or i2 do
print("***************")
if i1 then
i1, get1 = c1()
print("consumer_1: i:", i1, "get:", get1)
end
if i2 then
i2, get2 = c2()
print("consumer_2: i:", i2, "get:", get2)
end
end
consumer_1: i: 1 get: 10
consumer_2: i: 1 get: 20
***************
consumer_1: i: 2 get: 30
consumer_2: i: 2 get: 40
***************
consumer_1: i: 3 get: 50
consumer_2: i: 3 get: 60
***************
consumer_1: i: 4 get: 70
consumer_2: i: 4 get: 80
***************
consumer_1: i: 5 get: 90
consumer_2: i: 5 get: 100
***************
consumer_1: i: 6 get: 110
consumer_2: i: 6 get: 120
***************
consumer_1: i: 7 get: 130
consumer_2: i: 7 get: 140
***************
consumer_1: i: 8 get: 150
consumer_2: i: 8 get: 160
***************
consumer_1: i: 9 get: 170
consumer_2: i: 9 get: 180
***************
consumer_1: i: 10 get: 190
consumer_2: i: 10 get: 200
***************
consumer_1: i: nil get: nil
consumer_2: i: nil get: nil
之前看書的時候,不覺得與Python的generator有啥差別,只知道Lua的coroutine好像更靈活。這次深入了解,有所體會。
比起Python的generator,Lua的coroutine提供更加強大的功能,可以實現更加靈活的模式。
也更難使用、更難理解?