Sequentially running systems on other threads?
See original GitHub issueHey there. So I usually try to get the rendering of my games on another thread, as this process tends to not do any kind of updating or Set
ting of components. However, the examples of the usage of a runner
have only shown singular System
s.
I have a camera, and I’m thinking of making a CameraSystem
which takes the Entity
with the component Camera
. This will then call the SpriteBatch.Begin
process using the camera’s properties to view the game world.
After that, I would then sequence all my other world-space render calls so that they happen after the Begin
call and before the End
call. This would literally be the same as I would do it on my main thread anyway.
I’m not very clear on how Runner
s really work. I get that it allows you to run a system on another thread with ease, but I still need to call Update
otherwise my game stops rendering, so when exactly does the system Update
? If it waits for my call to it from my main thread, then surely it isn’t multithreaded? Little bit confused and would appreciate some help.
- What happens if you use the same runner for multiple systems? Can you sequence them?
- If not, would there be a way to use standard C# multithreading techniques to sequence the running of systems (that literally get and render, and don’t interfere with logic at all?)
- What exactly does
Update
do when a system is associated with a runner? Why is it necessary to call it?
Thanks very much for your hard work!
Issue Analytics
- State:
- Created 4 years ago
- Comments:9 (6 by maintainers)
Yes, when you
Set
a component value, an event will be sent to interested EntitySets so they can check the modified Entity (either Added or Changed). EntitySet and the class handling the component storage are not thread safe because I am lazy (and putting lock everywhere can’t be good for performance) so you don’t want those to happen in parallel. Note that even if your components are immutable you can still use the quick and dirtyGet
to change their valueThe Get does not do any check, do not send any event, and each entity should work on its own memory location so parallel processing is ok. If you want to use parallel processing but need to make composition changes on entities, you can use the EntityCommandRecorder to do so.
So I will have to answer your questions in the wrong order ^^
The main goal of
SystemRunner
is to split the process of a System on multiple thread so it is processed faster, not to run a system in the background. To give you a concrete example with anAEntitySystem
:This is a pretty basic system to update a position with a velocity. When you call its main Update method, it will run the
Update(float elaspedTime, in Entity entity)
on each entity of its internalEntitySet
. With aSystemRunner
, thisEntitySet
will be equally split on its threads, speeding up this process. The next interesting system class usingSystemRunner
is the ParallelSystem, it takes a collection of systems that will be run in parallel on the threads of theSystemRunner
, making sure that once you call itsUpdate
method, all the inner systems will also be updated once.There is two main system types to help you build a workflow of the update of your game:
SystemRunner
, this is in case you need a system to run on the main thread (like operations on the spriteBatch for example)You simply control the flow of your game by calling
Update
on the main system. Refer here for where it is safe to use aSystemRunner
(or tell me if it need more explanation).There is nothing wrong with reusing the same
SystemRunner
instance for multiple systems (it’s actually better to do so), as long as those systems don’t run at the same time!I believe that when you want to render your game state on the screen, you want what appear to be determined, as in not dependent on whether a logic system has finished running or not, you want your state to be stable. You could use a task to run a system in the background
but you will probably not like what you will end up on screen (or this system need to be completely independent of everything else). Using SequentialSystem/ParallelSystem to define your workflow help you to synchronize systems between each others so that for each update or frame, your game has run exactly one step, and everything is stable. You could define your own types to create a workflow if you do not want to use mine but I suspect you would end up with something really close.
Hopefully I didn’t forget anything here 😃