《Lua快速入门》8.协程

Lua 提供了协程(Coroutine)的支持,允许程序在单线程内实现并发执行。协程的切换由程序显式控制,而不是由操作系统调度,因此开销更小。

协程

1. 协程的基本概念

1.1 什么是协程?

协程(Coroutine)是一种用户态的轻量级线程,由程序显式控制调度。与操作系统线程不同,协程的切换不需要内核介入,因此开销更小。

1.2 协程的特点

  • 轻量级:协程的创建和切换开销远小于线程。
  • 协作式调度:协程的切换由程序显式控制,而不是由操作系统调度。
  • 非抢占式:协程只有在主动让出 CPU 时才会切换。

1.3 协程与线程的对比

特性协程线程
调度方式协作式抢占式
切换开销
并发性单线程内并发多线程并发
适用场景I/O 密集型任务CPU 密集型任务

2. 协程的创建与切换

2.1 协程的创建

Lua 使用 coroutine.create 函数创建协程,返回一个协程对象。

local co = coroutine.create(function()
    print("Hello from coroutine!")
end)

2.2 协程的启动与恢复

使用 coroutine.resume 启动或恢复协程的执行。

coroutine.resume(co)  -- 输出: Hello from coroutine!

2.3 协程的挂起

使用 coroutine.yield 挂起协程的执行,并返回一个值。

local co = coroutine.create(function()
    print("Start")
    coroutine.yield("Paused")
    print("End")
end)

print(coroutine.resume(co))  -- 输出: Start true Paused
print(coroutine.resume(co))  -- 输出: End true

2.4 协程的状态

使用 coroutine.status 检查协程的状态。

print(coroutine.status(co))  -- 输出: suspended

2.5 协程的返回值

协程可以通过 coroutine.yieldcoroutine.resume 传递值。

local co = coroutine.create(function()
    local x = coroutine.yield(10)
    print("Received:", x)
end)

local _, value = coroutine.resume(co)
print("Yielded:", value)  -- 输出: Yielded: 10
coroutine.resume(co, 20)  -- 输出: Received: 20

3. 协程在并发编程中的应用

3.1 协程与 I/O 操作

协程非常适合处理 I/O 密集型任务,如文件读写、网络请求等。

3.1.1 模拟异步 I/O
local function asyncIO(callback)
    local co = coroutine.create(callback)
    coroutine.resume(co)
end

asyncIO(function()
    print("Start I/O")
    coroutine.yield()
    print("End I/O")
end)

3.2 协程与事件循环

协程可以与事件循环结合,实现高效的并发编程。

3.2.1 简单事件循环
local tasks = {}

local function schedule(task)
    table.insert(tasks, task)
end

local function run()
    while #tasks > 0 do
        local task = table.remove(tasks, 1)
        coroutine.resume(task)
    end
end

schedule(coroutine.create(function()
    print("Task 1")
    coroutine.yield()
    print("Task 1 continued")
end))

schedule(coroutine.create(function()
    print("Task 2")
end))

run()

3.3 协程与生产者-消费者模型

协程可以用于实现生产者-消费者模型,解决生产者和消费者之间的同步问题。

3.3.1 生产者-消费者示例
local queue = {}
local maxSize = 5

local function producer()
    for i = 1, 10 do
        while #queue >= maxSize do
            coroutine.yield()
        end
        table.insert(queue, i)
        print("Produced:", i)
    end
end

local function consumer()
    for i = 1, 10 do
        while #queue == 0 do
            coroutine.yield()
        end
        local item = table.remove(queue, 1)
        print("Consumed:", item)
    end
end

local p = coroutine.create(producer)
local c = coroutine.create(consumer)

while coroutine.status(p) ~= "dead" or coroutine.status(c) ~= "dead" do
    coroutine.resume(p)
    coroutine.resume(c)
end

3.4 协程与网络编程

协程可以用于简化网络编程,处理并发连接。

3.4.1 使用协程处理多个连接
local socket = require("socket")

local function handleConnection(client)
    local co = coroutine.create(function()
        while true do
            local data = client:receive()
            if not data then break end
            print("Received:", data)
            client:send("Echo: " .. data .. "\n")
        end
        client:close()
    end)
    coroutine.resume(co)
end

local server = assert(socket.bind("127.0.0.1", 8080))
while true do
    local client = server:accept()
    handleConnection(client)
end

4. 总结

协程是 Lua 中一种强大的并发编程工具,具有轻量级、协作式调度的特点。通过协程,可以实现高效的 I/O 操作、事件循环、生产者-消费者模型和网络编程。掌握协程的使用方法,可以帮助开发者编写高性能的并发程序。

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页