Closed NoiSek closed 7 years ago
Closed indefinitely, it is not currently possible to introduce multithreading in a way that would actually improve performance.
Webworkers can only accept copies of items, meaning serializing all functions into strings, which must then be evaluated, and then performing deep clone JSON -> string -> JSON conversions of all arguments into those evaluated functions.
The amount of latency that we would have to start with for there to be a net performance increase with this method is quite high. (Providing a copy of tiles alone is a 4000 item array of objects, for example)
There's (possibly) still hope for using it just for A* pathing, but as a whole this is unlikely to be a worthwhile approach to consider for scripting as a whole.
Bumping this to the top of the queue, as the outcome of this affects the execution of a number of other things.
Webworkers have wide enough support (92-97%) on a number of major browsers that I think it's worth pursuing for the performance benefits. When unavailable, the engine can fall back to single threaded execution.
Important that we always write around single threading as a best case scenario, regardless, however. It would be bad practice to depend on the multi-threaded performance as the baseline.
State of things:
~5ms average when rendering a change in game state, give or take. Leaves us with 12.6ms, but it could be faster, and there are occasional dips to 20-30ms in certain situations (mostly when Redux performs a form of garbage collection as far as I can tell).
Current Execution Model (For reference)
Engine Level
GameReducer
to consumeScript Level
scriptResolver
checks if the actor has a script matching a given event in it's instance metadatascriptResolver
checks if the actor's parent entity / tile has a script matching a given eventscriptCompiler
scriptCompiler
checks if a script has already been compiled, and returns itscriptResolver
asksvariableResolver
for an argument instance to match every argument requirementPrimary problem with this approach is that depends on a single actor not stalling the entire execution thread, and secondarily that it is quite unpredictable in rendering speed (mostly due to A* pathing).
It would be nice to try a system where actor scripts are spawned in Worker processes and present the main thread with a list of changes to be made when complete. This gives the additional benefit of being able to timeout lagging processes by timing their execution.
Most likely, this probably means trading our middle-of-the-road unpredictable speed for a consistently slower but predictable one. Due to the nature of the conflict resolution that will have to occur, there will likely be some speed costs incurred, but it could be that the tradeoff will either be worth it or faster.
We'll see.