question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Sequentially running systems on other threads?

See original GitHub issue

Hey 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 Setting of components. However, the examples of the usage of a runner have only shown singular Systems.

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 Runners 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.

  1. What happens if you use the same runner for multiple systems? Can you sequence them?
  2. 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?)
  3. 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:closed
  • Created 4 years ago
  • Comments:9 (6 by maintainers)

github_iconTop GitHub Comments

1reaction
Dorakucommented, Nov 29, 2019

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 dirty Get to change their value

// Get returns a ref Component, you can see it as a Component*, this is its real address, not a copy
entity.Get<Component>() = new Component();

The 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.

1reaction
Dorakucommented, Nov 26, 2019

So I will have to answer your questions in the wrong order ^^

3. What exactly does Update do when a system is associated with a runner? Why is it necessary to call it?

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 an AEntitySystem:

[With(typeof(Velocity), typeof(Position)]
public sealed class VelocitySystem : AEntitySystem<float>
{
    public VelocitySystem(World world, SystemRunner<float> runner)
        : base(world, runner)
    { }

    protected override void Update(float elaspedTime, in Entity entity)
    {
        ref Velocity velocity = ref entity.Get<Velocity>();
        ref Position position = ref entity.Get<Position>();

        Vector2 offset = velocity.Value * elaspedTime;

        position.Value.X += offset.X;
        position.Value.Y += offset.Y;
    }
}

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 internal EntitySet. With a SystemRunner, this EntitySet will be equally split on its threads, speeding up this process. The next interesting system class using SystemRunner is the ParallelSystem, it takes a collection of systems that will be run in parallel on the threads of the SystemRunner, making sure that once you call its Update method, all the inner systems will also be updated once.

  1. What happens if you use the same runner for multiple systems? Can you sequence them?

There is two main system types to help you build a workflow of the update of your game:

  • SequentialSystem: define systems which need to be run one after the other because they are dependent of the execution of one another
// example in DefaultSlap sample
            _runner = new SystemRunner<float>(Environment.ProcessorCount);
            _system = new SequentialSystem<float>(
                new PlayerSystem(Window, _world), // handle the player input
                new HitSystem(_world), // check collisions to kill enemies, need the position and state of the player
                new GameSystem(_world), // spawn new enemies
                new AISystem(_world, _runner), // move the enemies
                new PositionSystem(_world, _runner), // just translate the position to screen coordinates
                new DrawSystem(_batch, _square, _world)); // draw everything
  • ParallelSystem: systems which can be run in parallel of each other (there is a constructor which take a system before the SystemRunner, this is in case you need a system to run on the main thread (like operations on the spriteBatch for example)
// example of what you want to achieve, but I am not sure of the SpriteBatch is thread safe, at least the End method needs to be called on the main thread I think
            _runner = new SystemRunner<float>(Environment.ProcessorCount);
            _system = new SequentialSystem<float>(
                new ActionSystem(_ => spriteBatch.Begin()), // ensure Begin is called before the other systems run
                new ParallelSystem(_runner,
                    new IndependantSystem1(),
                    new IndependantSystem2(),
                    new IndependantSystem3()),
                new ActionSystem(_ => spriteBatch.End()));

You simply control the flow of your game by calling Update on the main system. Refer here for where it is safe to use a SystemRunner (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!

// bad, don't mix it, you would probably end up in a deadlock
new ParallelSystem(_runner,
    new PositionSystem(_world, _runner),
    new AISystem(_world, _runner));

2. 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?)

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

Task.Run(() =>
{
    while (true)
    {
        system.Update(whatever);
    }
});

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 😃

Read more comments on GitHub >

github_iconTop Results From Across the Web

Run Java Threads sequentially
How will you execute Three threads sequentially? For eg. Thread1, Thread2, Thread3. It is not possible to pass the reference of one Thread...
Read more >
How can I make multiple threads to run sequentially?
Yes, a single program can run multiple threads at the same time, which is known as multithreading. In a multithreaded program, each thread...
Read more >
Do multiple software-threads on a single hardware- ...
An (operating) system may provide multiple threads to a process, and there is usually hardware support like interrupts used, even if the CPU...
Read more >
A thread is a single sequential flow of control within a ...
A thread is a single sequential flow of control within a program. Programs start, execute a series of instructions, and end. The execution...
Read more >
Multithreading and Concurrency - Java Programming Tutorial
A multi-thread program has an initial entry point (the main() method), followed by many entry and exit points, which are run concurrently with...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found