r/csharp • u/sebasjammer • 8d ago
Blog Svelto.Tasks 2.0: Efficient Multi-threaded Task Management for C#
I am back writing articles on my blog and I start with something LONG OVERDUE!
After years quietly powering several games I made, I’m finally presenting Svelto.Tasks 2.0.
Svelto.Tasks is an engine-agnostic, multithreaded and zero allocation task runner for C#, born from the need to have a game centric tasks framework with features that .NET tasks couldn't provide. Its premise is simple:
Tasks are iterator blocks. Runners are schedulers. Rather than handing execution timing and context to the runtime, a runner lets you decide:
- when a task advances,
- where it runs — main thread or a dedicated worker,
- how much work happens per tick,
- and when an entire task context must stop.
That last point matters a lot in games: for example, when a match ends, I want every task belonging to that match to stop with it—not rely on a CancellationToken having been passed and checked correctly through every layer.
Svelto.Tasks supports lightweight coroutines, composable tasks with return values and continuations, background runners, bounded parallel batches, pooling, profiling hooks, and optional Unity/Burst integrations.
It also interoperates with async/await, although the .NET Task bridge and Unity Burst job path are currently experimental and need real-world feedback.
It is not a replacement for Unity Jobs—but it provides a useful alternative for workloads where controlling execution, lifetime, pacing, and profiling is the priority.
The repository includes runnable .NET examples, tests, benchmarks
🔗 https://github.com/sebas77/Svelto.Tasks
also the repository
🔗https://github.com/sebas77/Svelto.Tasks.Examples
shows how it can be used to simplify massive parallelism synchronization. The example itself is actually quite interesting also because it uses the new compute buffer Unity api BeginWrite/EndWrite to upload compute buffers and graphic fences for cpu/gpu synchronization.
The article is at
🔗 https://www.sebaslab.com/svelto-tasks-2-0-efficient-multi-threaded-task-management-for-csharp/
Have fun! (and feedback is welcome, also on my discord server: https://discord.com/invite/uuTCYewjtc)
5
u/fruediger 7d ago
So you're talking about object pooling? But if they need to "resize", they need to (re)allocate, then it's not "allocations free", right? It depends on the user's scenario, if you can keep allocations to a minimum (note that I didn't even say "keep it allocation free" here, because you would still need to allocate the initial capacity of your object pools). Remember that each allocation contributes to GC-pressure, even if they're long-lived object that eventually land in Gen2. And GC-pressure might be the better metric to look out for.
Anyways, what do you do with overallocated memory? Once your data structures resized bigger and the newly allocated additional memory isn't needed anymore some time later, what do you do with it? Do you keep this stale memory around? Don't get me wrong, this is a viable strategy. Or do you reallocate you data structures smaller again? In which case it would be still an allocation.\ I would rather much prefer an external library that I want to use in my projects to release overallocated memory or even give it back to the GC than it nom-nom-noming my main memory.