LUA 协程 Coroutine

0
0
0
1. 云栖社区>
2. 博客>
3. 正文

## LUA 协程 Coroutine

Tinywan. 2017-07-19 16:54:09 浏览1727

# 协程 Coroutine

### 举个最原始的例子：

function greet()
print "hello world"
end

co = coroutine.create(greet) -- 创建 coroutine

print(coroutine.status(co))  -- 输出 suspended
print(coroutine.resume(co))  -- 输出 hello world
-- 输出 true (resume 的返回值)
print(coroutine.resume(co))  -- 输出 false    cannot resume dead coroutine (resume 的返回值)


### 函数 coroutine.yield(...)

OK，总结一下：当 co = coroutine.create(f) 时，yield 和 resume 的关系如下图：

### How coroutine makes life easier

#### 传统做法

-- 每帧的逻辑
function Monster:frame()
self:state_func()
self.state_frame_count = self.state_frame_count + 1
end

-- 切换状态
function Monster:set_next_state(state)
self.state_func = state
self.state_frame_count = 0
end

-- 首先向右走 30 帧
function Monster:state_walk_1()
local frame = self.state_frame_count
self:walk(DIRECTION_RIGHT)
if frame > 30 then
self:set_next_state(state_wait_for_player)
end
end

-- 等待玩家进入视野
function Monster:state_wait_for_player()
if self:get_distance(player) < self.range then
self.direction = -self:get_direction_to(player)
self:set_next_state(state_walk_2)
end
end

-- 向反方向走 15 帧
function Monster:state_walk_2()
local frame = self.state_frame_count;
self:walk(self.direction)
if frame > 15 then
self:set_next_state(state_wait_for_player)
end
end


#### 协程做法

-- 每帧的逻辑
function Monster:frame()
-- 首先向右走 30 帧
for i = 1, 30 do
self:walk(DIRECTION_RIGHT)
self:wait()
end

while true do
-- 等待玩家进入视野
while self:get_distance(player) >= self.range do
self:wait()
end

-- 向反方向走 15 帧
self.direction = -self:get_direction_to(player)
for i = 1, 15 do
self:walk(self.direction)
self:wait()
end
end
end

-- 该帧结束
function Monster:wait()
coroutine.yield()
end


Lua 把关于协程的所有函数放在一个名为 “coroutine” 的 table 里，coroutine 里具有以下几个内置函数：

-coroutine-yield [function: builtin#34]
|         -wrap [function: builtin#37]
|         -status [function: builtin#31]
|         -resume [function: builtin#35]
|         -running [function: builtin#32]
|         -create [function: builtin#33]


### coroutine.create - 创建协程

co = coroutine.create(function()
io.write("coroutine create!\n")
end)
print(co)


### coroutine.status - 查看协程状态

print(coroutine.status(co))


### coroutine.resume - 执行协程

coroutine.resume(co)


co = coroutine.create(function(a, b, c)
print("co", a, b, c)
end)
coroutine.resume(co, 1, 2, 3)


co = coroutine.create(function()
return 3, 4
end)
print(coroutine.resume(co))


### coroutine.yield - 中断协程运行

coroutine.yield 函数可以让一个运行中的协程中断挂起

co = coroutine.create(function()
for i = 1, 3 do
print("before coroutine yield", i)
coroutine.yield()
print("after coroutine yield", i)
end
end)
coroutine.resume(co)


coroutine.resume(co)

resume 执行完协程主函数或者中途被挂起（yield）时，会有返回值返回，第一个值是 true，表示执行没有错误。如果是被 yield 挂起暂停，yield 函数有参数传入的话，这些参数会接着第一个值后面一并返回

co = coroutine.create(function(a, b, c)
coroutine.yield(a, b, c)
end)
print(coroutine.resume(co, 1, 2, 3))


### 以 coroutine.wrap 的方式创建协程

function wrap(param)
print("Before yield", param)
obtain = coroutine.yield()
print("After yield", obtain)
return 3
end
resumer = coroutine.wrap(wrap)

print(resumer(1))

print(resumer(2))


### coroutine.running - 返回正在运行中的协程

print(coroutine.running())

co = coroutine.create(function()
print(coroutine.running())
print(coroutine.running() == co)
end)
coroutine.resume(co)

print(coroutine.running())


### resume-yield 交互

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
send(x)
end
end)
end

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

function consumer(prod)
--  repeat
--      print(type(x))
--      if x then
--          io.write(x, "\n")
--      end
--  until x == nil
while true do
if obtain then
io.write(obtain, "\n\n")
else
break
end
end
end

p = producer()
f = filter(p)
consumer(f)


Tinywan.
+ 关注