Multithreading Lua合作项目到底是为了什么?为什么';这段代码不能像我期望的那样工作吗?

Multithreading Lua合作项目到底是为了什么?为什么';这段代码不能像我期望的那样工作吗?,multithreading,lua,coroutine,Multithreading,Lua,Coroutine,我很难理解这个代码。。。我本来希望得到类似于线程的输出,其中随机的“nooo”和“yaaay”相互交错,因为它们都是异步打印的,但是我发现主线程似乎在第一次调用coroutine.resume()时就阻塞了从而防止在第一个屈服之前启动下一个 如果这是计划中的操作协同程序,它们有什么用处,我将如何实现我希望的目标?我是否必须为这些协同路由实现自己的调度程序以异步运行?因为这看起来很混乱,我也可以使用函数 co1 = coroutine.create(function () loca

我很难理解这个代码。。。我本来希望得到类似于线程的输出,其中随机的“nooo”和“yaaay”相互交错,因为它们都是异步打印的,但是我发现主线程似乎在第一次调用coroutine.resume()时就阻塞了从而防止在第一个屈服之前启动下一个

如果这是计划中的操作协同程序,它们有什么用处,我将如何实现我希望的目标?我是否必须为这些协同路由实现自己的调度程序以异步运行?因为这看起来很混乱,我也可以使用函数

co1 = coroutine.create(function ()
        local i = 1
        while i < 200 do
                print("nooo")
                i = i + 1
        end
        coroutine.yield()
end)

co2 = coroutine.create(function ()
        local i = 1
        while i < 200 do
                print("yaaaay")
                i = i + 1
        end
        coroutine.yield()
end)

coroutine.resume(co1)
coroutine.resume(co2)
co1=coroutine.create(函数()
局部i=1
而我呢
打印(“nooo”)
i=i+1
结束
协同程序。收益率()
(完)
co2=coroutine.create(函数()
局部i=1
而我呢
打印(“yaaay”)
i=i+1
结束
协同程序。收益率()
(完)
合作程序。恢复(co1)
合作程序恢复(co2)

协同程序不是线程

协同路由就像从不主动调度的线程。所以,是的,您是正确的,您必须编写自己的调度程序,使两个协同程序同时运行

然而,当涉及到合作项目时,你却忽略了大局。看看维基百科的。下面是一个具体的例子,它可能会指引你走向正确的方向

--级别脚本
--火山每两分钟喷发一次
功能级_与_火山(接口)
尽管如此
等待(秒(5))
开始喷发火山()
等待(帧(10))
s=播放(“隆隆声”)
等待(结束)
启动照相机抖动()
--更多的东西
等待(分钟(2))
结束
结束
上面的脚本可以编写为使用switch语句和一些巧妙的状态变量迭代运行。但如果将其写成协同程序,则更为清晰。上面的脚本可以是一个线程,但是您真的需要为这个简单的代码指定一个内核线程吗。繁忙的游戏级别可以运行100个这样的协同程序,而不会影响性能。然而,如果这些都是一个线程,那么在性能开始下降之前,您可能会得到20-30个线程


协同程序意味着允许我编写在堆栈上存储状态的代码,这样我就可以停止运行它一段时间(
wait
函数)从我结束的地方重新开始。

因为有很多评论询问如何实现
wait
函数,这将使
deft_code
的示例工作,所以我决定编写一个可能的实现。一般的想法是,我们有一个带有协同路由列表的调度器,在协同路由通过
wait
调用放弃控制后,调度器决定何时将控制权返回给协同路由。这是可取的,因为它使异步代码可读且易于推理

co1 = coroutine.create(
    function()
        for i = 1, 100 do
            print("co1_"..i)
            coroutine.yield(co2)
        end
    end
)

co2 = coroutine.create(
    function()
        for i = 1, 100 do
            print("co2_"..i)
            coroutine.yield(co1)
        end
    end
)

for i = 1, 100 do
    coroutine.resume(co1)
    coroutine.resume(co2)
end
这只是协同路由的一种可能用途,它们是一种更通用的抽象工具,可用于许多不同的目的(如编写迭代器和生成器、编写有状态流处理对象(例如,解析器中的多个阶段)、实现异常和连续性等)

第一:调度程序定义:

local function make_scheduler()
    local script_container = {}
    return {
        continue_script = function(frame, script_thread)
            if script_container[frame] == nil then
                script_container[frame] = {}
            end
            table.insert(script_container[frame],script_thread)
        end,
        run = function(frame_number, game_control)
            if script_container[frame_number] ~= nil then
                local i = 1
                --recheck length every time, to allow coroutine to resume on
                --the same frame
                local scripts = script_container[frame_number]
                while i <= #scripts do
                    local success, msg =
                        coroutine.resume(scripts[i], game_control)
                    if not success then error(msg) end
                    i = i + 1
                end
            end
        end
    }
end
游戏的(虚拟)界面:

local game_control = {
    seconds = function(num)
        return math.floor(num*fps)
    end,
    minutes = function(num)
        return math.floor(num*fps*60)
    end,
    frames = function(num) return num end,
    end_of = function(sound)
        return sound.start+sound.duration-frame_number
    end,
    wait = function(frames_to_wait_for)
        scheduler.continue_script(
            frame_number+math.floor(frames_to_wait_for),
            coroutine.running())
        coroutine.yield()
    end,
    start_eruption_volcano = function()
        --obviously in a real game, this could 
        --affect some datastructure in a non-immediate way
        print(frame_number..": The volcano is erupting, BOOM!")
    end,
    start_camera_shake = function()
        print(frame_number..": SHAKY!")
    end,
    play = function(soundname)
        print(frame_number..": Playing: "..soundname)
        return {name = soundname, start = frame_number, duration = 30}
    end
}
游戏循环:

while true do
    scheduler.run(frame_number,game_control)
    frame_number = frame_number+1
end

协同程序不是线程。它们是线程式的,因为它们是独立的执行环境,但您的程序是调度程序,它们不是抢占式的。我想添加一个完整的答案,但是我的Lua已经生锈了,所以我不能提供任何代码示例…谢谢,这很好地回答了我的问题@维克多,是的,你自己来实施。我添加了一些额外的东西,你可以看到Lua协同程序对于脚本来说是多么好。主程序(在C或Lua中)创建一个协同程序来运行
level\u和\u volcano
结束
,和
分钟
函数返回一种特殊类型的
等待
函数。
wait
函数使用该特殊类型来决定协同程序需要睡眠多长时间,并将该值生成给主程序。主程序继续处理它的业务(绘图、更新等),经过足够的时间后,它将恢复
level\u与\u volcano
corroutine。@deft\u code您能提供此特定用例的简化lua代码吗?我花了三个小时试图探索协同程序的概念,现在我觉得自己很愚蠢,因为我仍然无法实现您的示例。我知道这已经有一年多没有涉及过了,但我也想看看
wait
函数的代码实现。@Moop:TL;医生:嗯!基本的问题是,我并没有把“Lua线程”称为线程。所以你的评论是正确的,它们在技术上是Lua线程。对此我可以回答,它们不是线程,它们是协程。嗯,嗯,嗯,嗯,嗯,嗯。。。我们都是对的,但使用“线程”有两种不同的含义。现在有一个不太明智的答案:
coroutine.create
luaB\u-cocreate
实现,它在堆栈上返回一个
lua\u状态。
type
函数在收到
lua\u状态时返回
“thread”
while true do
    scheduler.run(frame_number,game_control)
    frame_number = frame_number+1
end