How should I use the c# job system with tasks that can take a couple seconds to complete?

Hello!

My understanding of the C# job system is still pretty limited. I have been able to use it and performance boosts with quick jobs that can be completed in one frame. However I have some tasks that take up to a couple seconds to complete that I usually would use traditional C# multi threading to complete.

I understand that I can use Allocator.Persistent for memory that needs to be stored longer than 4 frames. But the documentation states that “You should not use Persistent where performance is essential.”

So if I shouldn’t use this when performance is essential, but the task will take a couple seconds to complete, then should I use a C# job with Allocator.Persistent memory or should I stick to my traditional c# multithreading (that is much easier to use)?

Hello, I assumed that the performance concern for the persistant allocaction was only when you allocate.
So I use it if I need a memory sapce that I will use/reuse over a long period of time in my game/application instead of reallocating new memory every (couple of) frames.

I never actually tested if the read/write performance of a container was affected by the allocation type.

For your situation I guess it depends on what your long job does and what it uses.
If you have something like procedural terrain generation that may take some time but is effectively independant from the rest of your entities and/or there is no chance of taking advandage of Burst, I guess “normal” threading is fine.
If there is a chance of benefitting from Burst and/or there is a depandancy with other entities, I would stick with the job system to take advantage of the safety features.

3 Likes

Shouldn’t be the case, a pointer is a pointer (?).

One thing to consider is that these long running jobs could starve more important per-frame jobs by occupying workers. So depending on the workload and on the core/worker count you could see some issues. Haven’t tried this in practice.

Worker thread are thread in the end if the cpu is busy it’s busy. I don’t see it have an impact on performance weather it is job thread or normal thread.

There’s a performance difference based on where memory is allocated. Here’s an article:

But I’d say Jobs should be faster than default C# threading in most of the cases (at least because of Burst).

3 Likes

I think there could be some difference in the way work is scheduled.

I just ran a super quick test and apparently if you completely saturate the job workers with long-running jobs, Unity resorts to running per-frame jobs on the main thread (I guess this is to be expected when JobHandle.Complete is called). So the engine doesn’t exactly stall completely, but there is a noticable framerate drop because the long-running jobs aren’t interrupted by the (arguably more important) jobs related to frame simulation, rendering, etc.

IIUC, if you spin off your own thread (or use the .NET threadpool), it’s up to the OS to allocate it some time to do work. Of course, the thread would still be in contest with the job workers. Not sure if that’s better or worse for performance (probably “depends”).

2 Likes

I am using entities+burst+job system to generate an earth size planet with heightmap sampling and procedural noise generation. I use persistent allocators for it and complete jobs only when they are finished. It is still way way faster that c# threads. I gues c# threads are only choice when you need an explicit control over their lifetime, like an ability to interrupt them or so. In most cases burst and jobs will outperform them by several orders.

1 Like

If you have to create a thread first, then the will cost some performance. .NET Task use a thread pool the avoid this. Unity Job System uses with Background Worker Threads, which already exist and run on per logical core, thus no overhead for creating a thread. One reason why the job system is so fast is Burst, but also because the job system has controll over which thread the job is running. With a C # thread/task, it can also happen that he runs on the same core like the Mainthread. Job system tries to avoid this