Lua中协程实现学习笔记

最近在看协程相关的技术点,包括协程的概念,以及在PHP中的实现,可参考之前的内容《PHP中协程实现学习笔记》。

很早就知道Lua支持协程,之前在业务中使用lua的时候也没有了解过协程,完全处于好奇,简单了解了下,很浅的了解,以下是笔记。

一、简单回顾lua代码的执行

0、Linux环境下一般都默认安装的有lua脚步解释器

lua -v
Lua 5.1.4  Copyright (C) 1994-2008 Lua.org, PUC-Rio

1、Mac下可以直接通过brew安装

# 安装
brew install lua

# 查看
lua -v
Lua 5.3.5  Copyright (C) 1994-2018 Lua.org, PUC-Rio

2、测试脚本
以下代码保存文件test.lua

print('Hello Lua')

用过lua解释器直接执行即可

lua test.lua

Hello Lua

二、Lua协程相关的函数

Lua基础库的子库有一个协程库coroutine,主要包含以下函数
0、coroutine.create(f)
创建一个主体函数为f的新协程。 f必须是一个Lua的函数。 返回这个新协程,它是一个类型为 “thread” 的对象。

1、coroutine.resume(co [, val1, ···])
开始协程co的运行, 或者继续协程co的运行(如果co之前被挂起)。
注:如果协程第一次运行的话,参数var1会作为co的参数传递;如果是继续执行协程的话,参数var1会作为co中上一次yield的返回值。

Tip: resume除了摘要,还有重新开始的意思。

2、coroutine.yield()
挂起正在执行的协程

3、coroutine.status(co)
返回协程co的运行状态: running(运行中)、suspendded(挂起或还没开始运行)、normal(活动的,但并不在运行)、dead(运行完成或异常退出)

4、coroutine.running()
返回两个值: 在运行的协程(返回的是协程的ID), True/False(在主线程中返回True, 否则返回False)

三、Lua协程函数的使用

0、conroutine.resume的返回值
以下代码保存文件test.lua

co = coroutine.create(function (a, b)
    print("co-body", a, b)
    local r, s = coroutine.yield(a + b, a - b)
    print("co-body-after-yield", r, s)
    return b, "end"
end)

print("main", coroutine.resume(co, 1, 10))
print("main", coroutine.resume(co, 2, 3))

注:第二次调用coroutine.resume(), 因为执行的是同一个协程,所以是从yield这一行(包含这一行)开始执行。

执行结果

lua test.lua

co-body	                1	10
main	                true	11	-9 # yield的参数会作为第一次的返回值
co-body-after-yield	2	3 # 第二次执行,参数作为yield的返回值
main	                true	10	end

1、conroutine.running()的使用
分别调用coroutine.running()

co = coroutine.create(function (a, b)
    print("main", coroutine.running())
    
    print("co-body", a, b)
    local r, s = coroutine.yield(4, 4)
    print("co-body-after-yield", r, s)
    return b, "end"
end)

print("main", coroutine.running())

print("main", coroutine.resume(co, 1, 10))
print("main", coroutine.resume(co, 2, 3))

以上输出结果

main	thread: 0x7fd6eb001008	true
main	thread: 0x7fd6eac06a78	false
co-body	1	10
main	true	4	4
co-body-after-yield	2	3
main	true	10	end

2、更多函数用法
参考:简书-Lua Coroutine详解

四、Lua协程的应用

0、多协程协作运行

co1 = coroutine.create(
    function()
        for i = 1, 3 do
            print('co1_' .. i)
            -- lua没有sleep函数,调用OS的sleep功能sleep 3s
            os.execute("sleep " .. tonumber(3))
            print(coroutine.running())
            coroutine.yield()
        end
    end
)

co2 = coroutine.create(
    function()
        for i = 1, 3 do
            print('co2_' .. i)
            print(coroutine.running())
            coroutine.yield()
        end
    end
)

for i = 1, 3 do
    coroutine.resume(co1)
    coroutine.resume(co2)
end

以上输出

co1_1
thread: 0x7ff264406d88	false
co2_1
thread: 0x7ff2644070e8	false
co1_2
thread: 0x7ff264406d88	false
co2_2
thread: 0x7ff2644070e8	false
co1_3
thread: 0x7ff264406d88	false
co2_3
thread: 0x7ff2644070e8	false

五、总结&思考

0、Lua中有协程库,使用协程相对比PHP方便和易于理解不少。

1、协程实现并发,个人理解不是不有问题,多个协程是协作运行的,本身就是一个整体, 如果一个协程阻塞了,另外一个协程也会等待执行。比如上面co1 sleep(3)后,co2需要等待。

参考:
https://www.tutorialspoint.com/lua/lua_coroutines.htm
Lua 5.3 参考手册
https://timyang.net/lua/lua-coroutine/Stackoverflow: what-are-lua-coroutines-even-for

发表评论

电子邮件地址不会被公开。 必填项已用*标注