My Qt/C++ app uses worker threads (QThread) to improve performance for users with multicore processors. Each worker's job is to manipulate some data. Each worker minds it's own business and does not need to communicate with any other workers. They also don't perform any IO operations. Perfect use case!
The use of multithreading for this workload has delightfully improved performance by many factors over.
Running on a Ryzen 9 3900X (12 cores)
However, now each worker is also tasked with passing it's data through a Lua script. So, each worker get's it's own Lua script instance (an object containing it's own lua_State). The data is passed between the native code and the Lua script through userdata in the form of pointers to these things I call "SharedObjects." All I have to do is derive from this SharedObject class and boom, Lua can talk to it!
All my Lua workload does is some basic logic and calling native functions to allocate new things that derive from SharedObject and return them. Basically, it creates a lot of SharedObjects and connects them to each other in specific ways.
When the script has a light workload the multithreaded performance stays great.
But once the script has a heavy workload the performance drops as the thread count rises above 4.
Here's the results of the tests I ran:
I don't understand why a heavy workload causes performance to get worse as thread count goes up??? I would expect it to reach a maximum and flatline....
EDIT: I created a minimal reproducible example project that perfectly simulates the problem. I compiled with MSVC2010 (as per my real application). https://github.com/MRG95/LuaThreads
Explanation of GitHub project files:
- main.cpp: Entry point. Creates the workers and simulates a workload. A timer keeps track of how long it takes to complete the work.
- Lua/lua_script.h: The interface between the lua script and native code. Native methods and properties are accessed through Qt's
QMetaObjectimplementation. the functionvoid bindObject()sets up the connection. - worker.h: Defines the
Workerclass which gets moved to it'sQThreadviamoveToThread. The script function call happens invoid doWork(). - tags.h/tags.cpp: Example data types that get processed in the script.
In the build folder is a file testScript.lua that is the sample workload itself. It's just a simple loop running some of the methods found in the tags.h classes.
