协程
1. 协程的基本概念
1.1 什么是协程?
协程(Coroutine)是一种用户态的轻量级线程,由程序显式控制调度。与操作系统线程不同,协程的切换不需要内核介入,因此开销更小。
1.2 协程的特点
- 轻量级:协程的创建和切换开销远小于线程。
- 协作式调度:协程的切换由程序显式控制,而不是由操作系统调度。
- 非抢占式:协程只有在主动让出 CPU 时才会切换。
1.3 协程与线程的对比
特性 |
协程 |
线程 |
调度方式 |
协作式 |
抢占式 |
切换开销 |
低 |
高 |
并发性 |
单线程内并发 |
多线程并发 |
适用场景 |
I/O 密集型任务 |
CPU 密集型任务 |
2. 协程的创建与切换
2.1 协程的创建
Lua 使用 coroutine.create
函数创建协程,返回一个协程对象。
1
2
3
|
local co = coroutine.create(function()
print("Hello from coroutine!")
end)
|
2.2 协程的启动与恢复
使用 coroutine.resume
启动或恢复协程的执行。
1
|
coroutine.resume(co) -- 输出: Hello from coroutine!
|
2.3 协程的挂起
使用 coroutine.yield
挂起协程的执行,并返回一个值。
1
2
3
4
5
6
7
8
|
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
检查协程的状态。
1
|
print(coroutine.status(co)) -- 输出: suspended
|
2.5 协程的返回值
协程可以通过 coroutine.yield
和 coroutine.resume
传递值。
1
2
3
4
5
6
7
8
|
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
1
2
3
4
5
6
7
8
9
10
|
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 简单事件循环
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
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 生产者-消费者示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
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 使用协程处理多个连接
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
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 操作、事件循环、生产者-消费者模型和网络编程。掌握协程的使用方法,可以帮助开发者编写高性能的并发程序。