前置知识: Lua

协程与异步

3 minIntermediate2026/5/3

Lua协程机制与异步编程实践

1. 协程基础 | Coroutine Basics

1.1 协程概念

协程(Coroutine)是一种特殊的函数,可以在执行过程中挂起,并在后续恢复执行。与线程不同,协程是协作式的,而不是抢占式的:

 -
 local co = coroutine.create(function()
  print("协程开始执行")
  coroutine.yield() -- 挂起协程
  print("协程恢复执行")
  return "协程执行完成"
 end)
 print("协程状态:", coroutine.status(co)) -- 输出 suspended
 -
 coroutine.resume(co) -- 输出 协程开始执行
 print("协程状态:", coroutine.status(co)) -- 输出 suspended
 -
 local success, result = coroutine.resume(co) -- 输出 协程恢复执行
 print("协程状态:", coroutine.status(co)) -- 输出 dead
 print("协程返回值:", result) -- 输出 协程执行完成

1.2 协程状态

协程有四种状态:

  • suspended协程已创建但未运行,或已挂起
  • running协程正在执行
  • normal协程正在运行其他协程
  • dead协程执行完毕或出错
 local co = coroutine.create(function()
  print("协程状态:", coroutine.status(co)) -- 输出 running
 end)
 print("创建后:", coroutine.status(co)) -- 输出 suspended
 coroutine.resume(co) -- 输出 协程状态: running
 print("执行后:", coroutine.status(co)) -- 输出 dead

2. 协程的高级用法 | Advanced Coroutine Usage

2.1 协程迭代器

协程可以用来创建自定义迭代器

 function range(from, to)
  return coroutine.wrap(function()
  for i = from, to do
  coroutine.yield(i)
  end
  end)
 end
 -
 for i in range(1, 5) do
  print(i) -- 输出 1, 2, 3, 4, 5
 end

2.2 协程与生产者-消费者模式

 function producer()
  return coroutine.create(function()
  while  do
  local value = io.read()
  coroutine.yield(value)
  end
  end)
 end
 function consumer(prod)
  while  do
  local status, value = coroutine.resume(prod)
  if not value then break end
  print("消费:", value)
  end
 end
 -
 local prod = producer()
 consumer(prod)

3. 异步编程 | Asynchronous Programming

3.1 使用协程实现异步操作

在 Lua 中,可以使用协程来模拟异步操作:

 -
 function asyncOperation(callback)
  -- 模拟异步延迟
  print("开始异步操作")
  -- 这里可以是网络请求、文件IO等
  local timer = 3 -- 3秒后完成
  -- 模拟定时器
  local function checkTimer()
  timer = timer - 1
  if timer <= 0 then
  callback("异步操作完成")
  else
  print("等待中...")
  -- 这里应该使用实际的定时器API
  checkTimer()
  end
  end
  checkTimer()
 end
 -
 function asyncOperationWithCoroutine()
  local co = coroutine.running()
  asyncOperation(function(result)
  coroutine.resume(co, result)
  end)
  return coroutine.yield()
 end
 -
 local result = asyncOperationWithCoroutine()
 print("结果:", result) -- 输出 结果: 异步操作完成

3.2 协程事件循环

在游戏开发中,协程常与事件循环结合使用:

 -
 local events = {}
 function addEvent(event)
  table.insert(events, event)
 end
 function processEvents()
  while #events > 0 do
  local event = table.remove(events, 1)
  event()
  end
 end
 -
 function delay(seconds, callback)
  local startTime = os.time()
  local function checkTime()
  if os.time() - startTime >= seconds then
  callback()
  else
  addEvent(checkTime)
  end
  end
  addEvent(checkTime)
 end
 -
 function wait(seconds)
  local co = coroutine.running()
  delay(seconds, function()
  coroutine.resume(co)
  end)
  coroutine.yield()
 end
 -
 function moveCharacter()
  local co = coroutine.create(function()
  print("开始移动")
  wait(2) -- 等待2秒
  print("移动中...")
  wait(3) -- 再等待3秒
  print("移动完成")
  end)
  addEvent(function() coroutine.resume(co) end)
 end
 -
 moveCharacter()
 while  do
  processEvents()
  -- 这里应该有适当的休眠,避免CPU占用过高
 end

4. 协程的实际应用 | Practical Applications

4.1 游戏AI行为树

 function behaviorTree()
  return coroutine.create(function()
  while  do
  -- 检查玩家是否在视野内
  if playerInSight() then
  print("发现玩家,准备攻击")
  -- 移动到攻击位置
  moveToPlayer()
  coroutine.yield()
  -- 攻击玩家
  attackPlayer()
  coroutine.yield()
  else
  print("玩家不在视野内,巡逻")
  -- 巡逻
  patrol()
  coroutine.yield()
  end
  end
  end)
 end

4.2 网络请求处理

 function httpGet(url)
  local co = coroutine.running()
  -- 模拟网络请求
  print("发送请求到:", url)
  -- 模拟网络延迟
  local timer = 2
  local function checkTimer()
  timer = timer - 1
  if timer <= 0 then
  local response = "{\"status\": \"ok\", \"data\": \"success\"}"
  coroutine.resume(co, response)
  else
  print("等待响应...")
  checkTimer()
  end
  end
  checkTimer()
  return coroutine.yield()
 end
 -
 local co = coroutine.create(function()
  local response = httpGet("https://api.example.com/data")
  print("收到响应:", response)
  -- 处理响应数据
 end)
 coroutine.resume(co)

5. 协程的优缺点 | Pros and Cons

5.1 优点

  • 简化异步代码:使用协程可以编写看起来同步的代码,避免回调地狱
  • 状态管理协程可以保存执行状态,便于处理复杂的逻辑流程
  • 内存效率协程比线程更轻量级,占用更少的内存
  • 控制流清晰协程使代码的控制流更加清晰,易于理解和维护

5.2 缺点

  • 错误处理协程中的错误需要特殊处理
  • 调试困难协程的执行流程可能较难调试
  • 性能考虑:在某些情况下,协程的开销可能比直接使用回调更高

6. 总结 | Summary

  • 协程是 Lua 中强大的特性,允许函数在执行过程中挂起和恢复
  • 协程可以用来实现迭代器、生产者-消费者模式、异步操作等
  • 协程为异步编程提供了一种优雅的解决方案,避免了回调地狱
  • 在游戏开发和嵌入式系统中,协程特别有用,可以简化复杂的逻辑流程 通过掌握协程的使用,可以编写更加优雅、模块化的 Lua 代码,特别是在处理异步操作和复杂逻辑流程时。