Lua在多线程任务中对性能的影响随着线程数的增加而降低(包含条形图)
我的Qt/C++应用程序使用工作线程(QThread)来提高多核处理器用户的性能。每个工作线程的工作是操纵一些数据。每个工作线程都有自己的任务,不需要与其他工作线程通信,也不执行任何IO操作。这是完美的使用案例!
多线程用于这种工作量的使用,使性能快了很多倍。
在Ryzen 9 3900X(12核)上运行
但是,现在每个工作线程还负责通过Lua脚本传递它的数据。因此,每个工作线程都有自己的Lua脚本实例(包含自己的lua_State)。在本机代码和Lua脚本之间以指向这些我称之为“SharedObjects”的东西的指针的形式通过userdata传递数据。我所要做的就是从这个SharedObject类派生,并且,Lua就能与它交流!
我的所有Lua工作仅仅是进行一些基本的逻辑操作,并调用本机函数来分配从SharedObject派生的新的东西并返回它们。基本上,它创建了很多SharedObjects,并以特定的方式将它们连接在一起。
当脚本的负载轻时,多线程性能仍然很好。但是,一旦脚本的负载变重,随着线程数的增加,性能会下降到超过4。以下是我运行的测试结果:
我不明白为什么负载较重时,线程数增加会导致性能变差?我期望它能达到峰值并趋于平稳....
编辑:我创建了一个最小的可重现示例项目,完美模拟了问题。我使用MSVC2010(与我的实际应用程序相同)进行编译。https://github.com/MRG95/LuaThreads
GitHub项目文件的解释:
- main.cpp:入口点。创建工作者并模拟工作负载。计时器跟踪完成工作所需的时间。
- Lua/lua_script.h:Lua脚本和本机代码之间的接口。通过Qt的
QMetaObject实现访问本机方法和属性。函数void bindObject()设置了连接。 - worker.h:定义了通过
moveToThread移动到其线程的Worker类。脚本函数调用发生在void doWork()中。 - tags.h/tags.cpp:要在脚本中处理的示例数据类型。
在构建文件夹中有一个文件testScript.lua,它是样本工作负载本身。只是一个简单的循环,运行在tags.h类中找到的一些方法。
我得以解决问题,而问题与 Lua、QThread 或 CPU 缓存无关。这实际上很出乎意料。
问题出在 QMetaType 查找上。当比较 QMetaMethod 参数类型以确定 Lua 脚本所调用的本机函数时,我使用了方法 QMetaType::Type()。
当 Qt 查找类型时,它在全局范围内进行查找,这导致了这些多线程问题。答案是改为仅比较类型名称并完全避免所有 QMetaType 查找。
所以这段时间,是 Qt 挡住了我的路。他们的文档说 QMetaType 是线程安全的,确实是,但代价是会使其他线程在每次查找完成之前停止。使用我的新方法,在单线程使用情况下性能反而下降了,但在多线程中性能更好。将来,我计划根据运行的线程数在两者之间切换。
- Lua 虚拟机加密load(string.dump(function)) 后执行失败问题如何解决
- 我想创建一个 Nginx 规则,禁止访问
- 如何将两个不同的lua文件合成一个 东西有点长 大佬请耐心看完 我是小白研究几天了都没搞定
- 如何在roblox studio中1:1导入真实世界的地形?
- 求解,lua_resume的第二次调用继续执行协程问题。
- 【上海普陀区】内向猫网络招募【Skynet游戏框架Lua后端程序员】
- SF爱好求教:如何用lua实现游戏内调用数据库函数实现账号密码注册?
- Lua实现网站后台开发
- LUA错误显式返回,社区常见的规约是怎么样的
- lua5.3下载库失败
- 请问如何实现文本框内容和某个网页搜索框内容连接,并把网页输出来的结果反馈到另外一个文本框上
- lua lanes多线程使用
- 一个kv数据库
- openresty 有没有比较轻量的 docker 镜像
- 想问一下,有大佬用过luacurl吗
- 在Lua执行过程中使用Load函数出现问题
- 为什么 neovim 里没有显示一些特殊字符?
- Lua比较两个表的值(不考虑键的顺序)
- 有个lua简单的项目,外包,有意者加微信 liuheng600456详谈,最好在成都
- 如何在 Visual Studio 2022 中运行 Lua 代码?


这可能是错误的。了解更多关于 QThread 的内容。也许你应该使用
Qt::QueuedConnection。假设每个
QThread都运行着它自己的 Lua 解释器和状态(你应该研究一下你的 Lua 解释器的源代码,但它可能有一些 GIL,或者实际上需要一个)。我们无法猜测你的源代码,但你可能想使用 _Per-Thread Event Loop_,并且让每个 Lua 解释器在自己的 QThread 中运行,并在全局共享状态数据上使用一些细粒度的 QMutex。因此,每个小而短的 Lua 原语都将使用一些共享的
QMutex。记住,Qt 图形操作只允许在主线程(连接到 Linux 上的 Xorg 服务器)中进行。
这可能与 CPU 缓存 和 缓存一致性 有关。当所有活动线程和进程的数量超过内核数时,不要期望有神奇的性能缩放。
我不确定这是正确的,而且在没有看到你的源代码的情况下,我认为这可能是错误的。瓶颈很可能在你自己的代码中(你没有展示出来)。要确定,可以研究一下 Lua 的源代码。
你可以使用性能分析工具(在 Linux 上,gprof(1) 或 perf(1))。如果你使用 GCC 编译你的 C++ 代码和 Lua 的源代码,你可能需要 调用它。