Lua CallbackHell优化
概述
在异步操作中,常常要使用回调。但是,回调的嵌套常常会导致逻辑混乱,一步错步步错,难以维护。在Lua中,可以使用协程进行优化。
问题分析
模拟一个回合制游戏攻击过程
local function PlayAnim(anim, cb)
print("开始播放 " .. anim)
os.execute("sleep " .. 1)
print("播放完成 " .. anim)
cb()
end
local function Main()
print("行动开始")
PlayAnim("移动到目标动画",function()
print("开始攻击")
PlayAnim("攻击动画",function()
print("返回到原位置")
PlayAnim("返回动画",function()
print("行动结束")
end)
end)
end)
end
Main()
输出:

- 可以看到异步回调的嵌套导致代码结构混乱
Lua协程
简介
- Lua 协同程序(coroutine)与线程比较类似:拥有独立的堆栈,独立的局部变量,独立的指令指针,同时又与其它协同程序共享全局变量和其它大部分东西。
- 线程与协同程序的主要区别在于,一个具有多个线程的程序可以同时运行几个线程,而协同程序却需要彼此协作的运行。在任一指定时刻只有一个协同程序在运行,并且这个正在运行的协同程序只有在明确的被要求挂起的时候才会被挂起。
- 协同程序有点类似同步的多线程,在等待同一个线程锁的几个线程有点类似协同。
- coroutine在底层实现就是一个线程。
API
| API | 说明 |
|---|---|
| coroutine.create() | 创建 coroutine,返回 coroutine, 参数是一个函数,当和 resume 配合使用的时候就唤醒函数调用 |
| coroutine.resume() | 重启 coroutine,和 create 配合使用 |
| coroutine.yield() | 挂起 coroutine,将 coroutine 设置为挂起状态,这个和 resume 配合使用能有很多有用的效果 |
| coroutine.status() | 查看 coroutine 的状态。注:coroutine 的状态有三种:dead,suspended,running |
| coroutine.wrap() | 创建 coroutine,返回一个函数,一旦你调用这个函数,就进入 coroutine,和 create 功能重复 |
| coroutine.running() | 返回正在跑的 coroutine,一个 coroutine 就是一个线程,当使用running的时候,就是返回一个 corouting 的线程号 |
详细介绍
请参考跳转链接:菜鸟教程-协程
解决方案
function AsyncFunc(func)
return function(...)
local current_co = coroutine.running()
local ret, res = false, nil
local function cb(...)
if not coroutine.resume(current_co, ...) then
ret = true
res = ...
end
end
local params = table.pack(...)
table.insert(params, cb)
func(table.unpack(params))
if not ret then
res = coroutine.yield()
end
return res
end
end
function BeginTask(func, ...)
local t = coroutine.create(func)
coroutine.resume(t, ...)
end
local function PlayAnim(anim, cb)
print("开始播放 " .. anim)
os.execute("sleep " .. 1)
print("播放完成 " .. anim)
cb()
end
local AsyncPlayAnim = AsyncFunc(PlayAnim)
local function Main()
print("行动开始")
AsyncPlayAnim("移动到目标动画")
print("开始攻击")
AsyncPlayAnim("攻击动画")
print("返回到原位置")
AsyncPlayAnim("返回动画")
print("行动结束")
end
BeginTask(Main)
输出:

- 用AsyncFunc和BeginTask分别对异步函数和协程创建和运行做了封装
- 注意:不能在主协程中运行AsyncFunc,用BeginTask开启一个新的协程运行Main
Lua CallbackHell优化的更多相关文章
- Lua性能优化
原文:Lua Performance Tips 偶然找到<Lua Performance Tips>这篇关于Lua的优化文章,个人认为相较于多数泛泛而谈要好不少.尽管Lua已经到5.2版本 ...
- lua使用优化建议
1.使用局部变量local 这是最基础也是最有用的策略,虽然使用全局变量并不能完全避免,但还是应该尽量避免,取而代之使用局部变量即local.这里的局部变量也包括函数function,因为在Lua里函 ...
- lua 优化
彻底解析Android缓存机制——LruCache https://www.jianshu.com/p/b49a111147ee lua:部分常用操作的效率对比及代码优化建议(附测试代码) https ...
- Lua中如何实现类似gdb的断点调试--05优化断点信息数据结构
在上一篇04优化钩子事件处理中,我们在钩子函数中引入了call和return事件的处理,对性能进行了优化. 细心的同学可能已经发现了,我们的hook函数中call事件和line都需要对整个断点表进行遍 ...
- iOS app性能优化的那些事
iPhone上面的应用一直都是以流畅的操作体验而著称,但是由于之前开发人员把注意力更多的放在开发功能上面,比较少去考虑性能的问题,可能这其中涉及到objective-c,c++跟lua,优化起来相对 ...
- app 性能优化的那些事
来源:树下的老男孩 链接:http://www.jianshu.com/p/5cf9ac335aec iPhone上面的应用一直都是以流畅的操作体验而著称,但是由于之前开发人员把注意力更多的放在开发功 ...
- cloudflare的新waf,用Lua实现的
我们使用nginx贯穿了我们的网络,做前线web服务,代理,流量过滤.在某些情况下,我们已经扩充了nginx上我们自己的模块的核心C代码,但近期我们做了一个重大举措,与nginx结合使用lua 差点儿 ...
- 用好lua+unity,让性能飞起来——luajit集成篇/平台相关篇
luajit集成篇 大家都知道luajit比原生lua快,快在jit这三个字上. 但实际情况是,luajit的行为十分复杂.尤其jit并不是一个简单的把代码翻译成机器码的机制,背后有很多会影响性能的因 ...
- ESP8266开发综合篇(LUA开发-视频教程总揽)
为了解决基础教程简单入门但不实用,项目方案非常实用但比较难的问题,开始推出8266开发综合篇 综合篇涉及到AT,LUA,SDK,LUA(sdk)开发,LUA和SDK开发会同步进行,后期再整理AT指令的 ...
随机推荐
- 记一次排查线上MySQL死锁过程,不能只会curd,还要知道加锁原理
昨晚我正在床上睡得着着的,突然来了一条短信. 啥,线上MySQL死锁了,我赶紧登录线上系统,查看业务日志. 能清楚看到是这条insert语句发生了死锁. MySQL如果检测到两个事务发生了死锁,会回滚 ...
- SQL SERVER 算法面试题,自己再插入数据时,本想一次性复制10条数据,结果变成了1024条。产生一个算法bug,最后记录一下
- 微服务追踪SQL(支持Isto管控下的gorm查询追踪)
效果图 SQL的追踪正确插入到微服务的调用链之间 详细记录了SQL的执行内容和消耗时间 搜索SQL的类型 多线程(goroutine)下的追踪效果 在 Kubernetes 中部署微服务后,通过 Is ...
- C语言输出九九乘法表
C语言学了有一阵子了,趁着假期没事练练手,没想到挺简单 基本思路是这样的 先写一个主函数,然后定义两个变量i1和i2;使用for语句循环嵌套,外层循环负责写循环9次,内循环里面写从1开始递增去和外层循 ...
- ReentrantLock 公平锁源码 第1篇
ReentrantLock 1 这篇还是接着ReentrantLock的公平锁,没看过第0篇的可以先去看上一篇https://www.cnblogs.com/sunankang/p/16456342. ...
- springboot和mybatis 配置多数据源
主数据源(由于代码没有办法复制的原因,下面图片和文字不一致) package com.zhianchen.mysqlremark.toword.config;import com.zaxxer.hik ...
- STM32与物联网02-网络数据收发
在上一节中,介绍了 ESP8266 的使用方法.不过上一节中都是通过串口调试工具手动发送信息的方式来操作 ESP8266 ,这肯定不能用于实际开发.因此,本节介绍如何编写合适的程序来和 ESP8266 ...
- 作业二、安装CentOS7.9
一.安装环境 1.VMware Workstation 16 Pro 2.CentOS7.9 二.部署系统 步骤1.进入VMware,点击创建新的虚拟机 步骤2.进入新建虚拟机向导,选择典型(推荐) ...
- Taurus.MVC 如何升级并运行在NET6、NET7
前言: 之前计划帮某公司架构一个从WPF转向Web的低代码的开发平台,并构思为Taurus.MVC 新增微服务的基础功能模块,提供便捷的微服务开发方式,因中途合作中止,代码开发部分后续再上. 最近看到 ...
- 基于 Hexo 从零开始搭建个人博客(五)
阅读本篇前,请先阅读前几篇文章: 基于 Hexo 从零开始搭建个人博客(一) 基于 Hexo 从零开始搭建个人博客(二) 基于 Hexo 从零开始搭建个人博客(三) 基于 Hexo 从零开始搭建个人博 ...