Lua 学习 chapter24

1.8k 词

目录

  1. 协程

人人真真的生活过,学习过,改变过,努力过,才能创造出一个满意的自己。

协程

协程是一系列的可执行语句,拥有自己的栈、局部变量和指令指针,同时协程又与其他协程共享了全局变量和其他几乎一切资源。线程和协程的主要区别在于,一个线程程序可以并行运行多个线程,而协程却需要彼此协作的运行,即任意指定时刻只能有一个协程运行。

协程相关的函数都在coroutine表中,其中create为创建协程函数,参数为协程要执行的代码函数。它会返回一个thread类型的协程。 一个协程拥有四种状态:挂起,运行,正常和死亡。 当一个协程被创建的时候,它处于挂起状态。函数resume用于启动或再次启动一个协程的运行,并将其状态由挂起改为运行。协程函数执行完毕之后进入死亡状态。当使用协程A唤醒协程B的时候,协程A即不是挂起状态(因为不能唤醒协程A),也不是运行状态(因为B正在运行)。所以A此时的状态就被称为正常状态。

lua语言一个非常有用的机制是通过一对resume-yield来交换数据,第一个resume函数(没有对应等待它的yield)会把所有额外参数传递给协程的主函数。 在函数resume的返回之中,第一个返回值为true时表示没有错误,之后的返回值对应函数yield的参数。

可以将唤醒协程的函数放在一个函数中,因为这种模式比较常见,所以lua语言专门提供了一个特殊的函数coroutine函数来完成这个功能。 当执行wrap中的函数时候,就唤醒协程。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
co = coroutine.create(function(a, b, c)
    return a + b + c
end)

print(coroutine.resume(co, 1, 2, 3)) –> true 6。执行状态和结果

co = coroutine.create(function(a, b, c)
print(coroutine.yield(a + b, b + c)) –2 4 6,返回值是唤醒这个yield的参数值
return a + b + c
end)

print(coroutine.resume(co, 1, 2, 3)) – true 3 5,返回yield的参数,是最开始传进来的参数
print(coroutine.resume(co, 2, 4, 6)) – true 6,返回结果,根据最开始传进来的参数
print(coroutine.resume(co, 2, 4, 6)) –false cannot resume dead coroutine

function permutations(a)
return coroutine.wrap(function() permgen(a) end)
end

生产者与消费者的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
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

function filter(prod)
return coroutine.create(function()
for line = 1, math.huge do
local x = receive(prod)
x = string.format("%5d %s", line, x)
send(x)
end
end)
end

function consumer(prod)
while true do
local x = receive(prod)
io.write(x, "n")
local exit = string.match(x, "%l+")
if tostring(exit) == "q" then
break
end
end
end

consumer(filter(producer()))

            <hr style="visibility: hidden;"/>
            
            <hr style="visibility: hidden;"/>