协程基础与核心概念
1 ) 定义与特点
轻量级线程:在单线程内实现多任务协作,由程序显式控制切换(非抢占式)
资源开销低:每个协程独立堆栈(通常KB级),远低于操作系统线程(MB级)
适用场景:I/O密集型任务、状态机、游戏AI、异步逻辑等
2 ) 协程 vs 多线程
| 特性 | 协程 | 多线程 |
|---|---|---|
| 调度权 | 程序显式控制(yield) | 操作系统抢占式调度 |
| 并发性 | 协作式单核并发 | 并行/多核并发 |
| 数据同步 | 无需锁(单线程内) | 需互斥锁/信号量 |
2.1 示例:创建与启动协程
lua
local co = coroutine.create(function(a, b)
print("协程执行:", a, b)
local result = coroutine.yield(a + b) -- 挂起并返回a+b
print("恢复执行,接收参数:", result)
return "结束"
end)
local ok, sum = coroutine.resume(co, 10, 20) -- 启动协程,传入参数
print("首次resume结果:", ok, sum) -- 输出: true, 30
ok, msg = coroutine.resume(co, "新数据") -- 恢复协程,传入"新数据"
print("二次resume结果:", ok, msg) -- 输出: true, "结束"
2.2 示例:多个协程协作处理任务
lua
local co1 = coroutine.create(function()
for i = 1, 3 do
print("协程1执行步骤", i)
coroutine.yield() -- 暂停,让出控制权
end
print("协程1完成")
end)
local co2 = coroutine.create(function()
for i = 1, 3 do
print("协程2执行步骤", i)
coroutine.yield() -- 暂停,让出控制权
end
print("协程2完成")
end)
--- 主线程调度两个协程交替执行
print("开始执行协程1")
coroutine.resume(co1)
print("开始执行协程2")
coroutine.resume(co2)
print("再次执行协程1")
coroutine.resume(co1)
print("再次执行协程2")
coroutine.resume(co2)
print("第三次执行协程1")
coroutine.resume(co1)
print("第三次执行协程2")
coroutine.resume(co2)
3 ) 协程生命周期与关键函数
3.1 状态流转
coroutine.create
coroutine.resume
yield
执行完毕
创建
Suspended
Running
Dead
3.2 核心函数解析
-
coroutine.create(f)- 创建协程,返回thread对象(状态为suspended)
-
coroutine.resume(co, ...)- 启动或恢复一个协程的执行
- 首次调用:参数传递给协程函数
- 后续调用:参数作为yield的返回值
- 如果协程处于挂起或正常(normal)状态,resume会使其运行
- 当协程执行到yield或结束时,控制权返回给resume的调用者
-
coroutine.yield(...):- 在协程内部调用,使协程暂停执行并返回到resume调用处
- 协程的状态变为"挂起"
- 挂起协程,参数作为resume的返回值
- 恢复时接收resume传入的新参数
-
状态检查示例
luaprint(coroutine.status(co)) -- 输出: suspended(创建后) → running(执行中) → dead(结束)
示例代码
lua
--- 示例:演示协程生命周期
local co = coroutine.create(function(a, b)
print("协程开始执行,参数:", a, b)
local result = coroutine.yield("中间结果") -- 暂停并返回值
print("协程恢复执行,从yield接收到:", result)
return "最终结果"
end)
print("协程状态:", coroutine.status(co)) -- suspended
print("启动协程:")
local success, value = coroutine.resume(co, 10, 20) -- 传递参数给协程主函数
print("resume返回:", success, value) -- true, "中间结果"
print("协程状态:", coroutine.status(co)) -- suspended
print("再次启动协程:")
success, value = coroutine.resume(co, "恢复数据") -- 传递数据给yield
print("resume返回:", success, value) -- true, "最终结果"
print("协程状态:", coroutine.status(co)) -- dead
4 ) 协程与多任务处理
4.1 协作式多任务原理
事件循环调度:主线程轮询唤醒多个协程,避免阻塞[5]。
适用场景:网络请求批处理、游戏NPC行为序列[26]。
lua
--- 模拟多任务调度器
local tasks = {}
local function add_task(f) table.insert(tasks, coroutine.create(f)) end
-- 任务示例:模拟耗时操作
add_task(function()
for i = 1, 3 do
print("Task1: step", i)
coroutine.yield()
end
end)
add_task(function()
for i = 1, 2 do
print("Task2: step", i)
coroutine.yield()
end
end)
-- 调度执行
while #tasks > 0 do
for i = #tasks, 1, -1 do
local ok = coroutine.resume(tasks[i])
if coroutine.status(tasks[i]) == "dead" then
table.remove(tasks, i)
end
end
end
-- 输出交替执行步骤:Task1:step1 → Task2:step1 → Task1:step2 → ...
5 ) 协程在并发模型中的应用
5.1 生产者-消费者模式
lua
local function producer()
local i = 0
return function() -- 迭代器工厂
i = i + 1
if i <= 5 then
coroutine.yield("数据-" .. i) -- 生产数据并挂起
end
end
end
local co_producer = coroutine.wrap(producer()) -- 简化resume调用
local function consumer()
while true do
local data = co_producer()
if not data then break end
print("消费:", data) -- 输出: 数据-1, 数据-2, ...
end
end
consumer()
5.2 非阻塞I/O处理(模拟)
lua
--- 异步HTTP请求模拟
local function async_http(url, callback)
print("发起请求:", url)
coroutine.yield() -- 挂起协程,等待响应
callback("响应数据:" .. url)
end
--- 协程管理多个请求
coroutine.wrap(function()
async_http("api/user", function(data) print(data) end)
async_http("api/orders", function(data) print(data) end)
end)()
--- 事件循环模拟响应
for _ = 1, 2 do
coroutine.resume(main_co) -- 恢复协程,触发回调
end
6 ) 高级技巧与陷阱
6.1 协程复用
lua
local worker = coroutine.create(function(f, args)
while f do
f, args = coroutine.yield(f(table.unpack(args)))
end
end)
--- 复用协程执行不同函数
coroutine.resume(worker, math.abs, {-10}) -- 输出: 10
coroutine.resume(worker, string.upper, {"hello"}) -- 输出: HELLO
6.2 错误处理
pcall包裹resume捕获异常:
lua
local ok, err = pcall(coroutine.resume, co, bad_arg)
总结
| 场景 | 协程优势 |
|---|---|
| I/O密集型任务 | 避免回调地狱,代码线性化 |
| 游戏逻辑 | 简化状态机,NPC行为序列 |
| 资源受限环境 | 低内存开销(对比线程) |