什么是线程和协程的主要区别?与线程的区别

什么是线程和协程的主要区别?与线程的区别

什么是协程?

从多线程的角度来看,协程类似于线程:协程是一系列可执行语句,有自己的栈、局部变量和指令指针,协程与其他协程通信。进程共享全局变量和几乎所有其他内容。

线程和协程的主要区别:

一个多线程程序可以同时并行运行多个线程,但是协程需要相互协同运行,即任何时候只能运行一个协程,协程的切换是手动控制的用户模式。只有当正在运行的协程的显式要求被挂起时,正在运行的协程的执行才会被挂起。

Lua 中的协程支持提供库函数

Lua中所有与协程相关的函数都放在协程表中。

注意:方括号是可选参数

函数原型函数补充

coroutine.create(function object) -> coroutine object

创建协程对象并返回

类型(协程对象)=线程

coroutine.resume(coroutine object, [parameters 1, 2, 3...] 传递给协程函数) -> state, value

开始/继续执行协程

正常执行:返回true和yield返回值;发生未捕获的错误:返回 false 和错误消息

coroutine.yield([返回值])

暂停当前运行的协程

coroutine.status(协程对象)->状态

返回协程状态

create和yield后,挂起(suspended);执行过程正在运行(running);执行完毕就死了(dead);唤醒A协程中的B协程,则A协程处于正常(normal)状态。

coroutine.wrap(协程体函数)->函数

创建一个新的协程,以传入的函数作为主函数并返回一个函数

返回函数和resume类似,不同的是调用不会返回状态,只返回值,如果发生错误3D交通工具,会抛出异常。

使用示例

如果我们需要计算并打印一个斐波那契数列,假设每一步计算需要一秒,传统的写法可以是这样的:

function Fibonacci(n)
    local tab = {}
    local a, b = 1, 1
    for i = 1, n do
        table.insert(tab, a)
        local t = a + b
        a = b
        b = t
        Sleep(1)
    end
    return tab
end
local fib = Fibonacci(10)
for i, v in ipairs(fib) do
    io.write(v.." ")
end

运行结果:

1 1 2 3 5 8 13 21 34 55

运行过程:

等待 10 秒进行计算unity 协程和线程区别,然后立即打印所有结果。

计算过程卡住10秒显然不好。这个问题可以通过协程来优化。

协程计算可以这样写:

local coro = nil
function Fibonacci(n)
    local a, b = 1, 1
    for i = 1, n do
        coroutine.yield(a)      --挂起当前协程,并返回结果
        local t = a + b
        a = b
        b = t
        Sleep(1)
    end
end
    
coro = coroutine.create(Fibonacci)
function GetFibonacciNext()
    --开始/继续执行一个协程   正常执行:返回true和yield返回值   发生一个未捕获错误:返回false和错误信息
    local state, value = coroutine.resume(coro, 10)         
    return value
end
for i = 1, 10 do
    io.write(GetFibonacciNext().." ")
end

运行结果:

1 1 2 3 5 8 13 21 34 55

运行过程:

每计算一个结果(间隔1秒),立即返回并打印该值,直到打印10个序列项。

这种操作方式显然会更加友好,即在需要数据的时候进行计算。

使用协程作为迭代器

上面的遍历结果也可以改成迭代器的用法:

-- 把协程用作迭代器
function GetFibonacciNext(n)
    local co = coroutine.create(Fibonacci)
    return function()
        local state, value = coroutine.resume(co, n)
        return value
    end
end
for v in GetFibonacciNext(10) do
    io.write(v.." ")
end

这样写也能达到同样的效果,像迭代器一样用起来会更方便。

因为GetFibonacciNext的写法很常见unity 协程和线程区别硬件设备,唤醒对应协程的调用被包裹在一个函数中,所以Lua语言特地提供了一个函数coroutine.wrap来完成这个功能。 (上表详细介绍了wrap。)

使用 wrap 函数我们可以将 GetFibonacciNext 函数更改为以下代码:

function GetFibonacciNext(n)
    return coroutine.wrap(function() Fibonacci(n) end)
end

效果是一样的。

参考:《Lua 编程》第 24 章