Concurrency, Parallelism, and Frame Budgets
Bevy has three distinct forms of concurrency.
Parallel schedule execution
The multithreaded executor combines two graphs:
- dependency edges say what must finish first;
- component/resource access says what may safely overlap.
Query<&Position> can run beside another reader. Query<&mut Position>
conflicts with both. Disjoint filters may allow more precise compatibility.
Ready systems execute on ComputeTaskPool; completion events unlock dependents.
Parallel iteration inside one system
A system can use parallel query iteration when one system owns the relevant access but the entity set can be partitioned safely. This is nested data parallelism, distinct from running several systems.
Background async work
Assets use IoTaskPool; longer async computation has AsyncComputeTaskPool.
These tasks may outlive a frame and return owned results or update thread-safe
service state. They must not retain ordinary world borrows across suspension.
Barriers are deliberate
Exclusive systems, non-Send parameters, dependencies, and ApplyDeferred
reduce parallelism because they protect real invariants. A faster schedule that
observes half-applied entity structure would be incorrect.
The scheduler therefore optimizes a constrained problem:
maximize ready compatible work
subject to dependency, access, thread-affinity, and mutation barriers
Frame latency also matters more than aggregate throughput. An unbounded system or background-result integration step can still miss the frame budget even if all memory access is safe.