Multithreading in mobile games and builds WebGL how is it different?
Minh Khoa
Author
In short: Mobile supports normal C# threads# and the Job System. Unity Web, on the other hand,
Thread/Task.Runstill does not support them; only from Unity 6.4C## Jobs can[BurstCompile]be run in parallel if configured correctly.
Version matters a lot: Unity 6.3 LTS and 6.4+ behave differently. On 6.3C## on the Web, there is still only one thread. In 6.4Burst Jobs are the exception and can use real worker threads.
## Simply put
- Mobile: the kitchen has many sous-chefs. You can assign work through Thread, Task, or the Job System.
- Web 6.3: has only one C# chef#. Coroutines only help the chef switch to another task while waiting; they do not create more people.
- Web 6.4: also has an extra team of sous-chefs, but they only accept “work tickets” that have been Job System + Burst standardized.
Mobile: Main ─┬─ Task / Thread
└─ Jobs / Burst ──► worker threads
Web 6.3: Main ──► toàn bộ C#
Web 6.4: Main ─┬─ C# thông thường
└─ Burst Jobs ─────► worker threads
Quick comparison
| Task | Mobile | Web 6.3 | Web 6.4+ |
|---|---|---|---|
Thread, Task.Run | Usable | Not supported | Still not supported |
| Jobs without Burst | Can run on worker | Run on main thread | Run on main thread |
Jobs with [BurstCompile] | Run in parallel | Not yet running in parallel | Can run in parallel |
| Coroutine / Awaitable | Asynchronous, does not create threads by itself | Asynchronous | Asynchronous |
| Edit GameObject / Transform / UI | Main thread | Main thread | Main thread |
Mobile: work can be moved to another thread
For example, heavy data computation that does not need Unity API:
async Awaitable<int> CalculateOnMobile(int[] input)
{
await Awaitable.BackgroundThreadAsync();
// Chỉ tính dữ liệu thuần, không gọi GameObject hay Transform.
int result = HeavyCalculation(input);
await Awaitable.MainThreadAsync();
return result;
}
Mobile runs natively on Android/iOS so background threads can use CPU different cores.
But do not move everything to a worker thread. Creating GameObject, editing Transform, Animator or UI still has to be done on the main thread. With many small calculations on large arrays, Job System + Burst is often easier to control and more efficient than creating a large number of Tasks yourself.
Web 6.4: real multithreading, but only through Burst Jobs
Example of a job processing many elements:
using Unity.Burst;
using Unity.Collections;
using Unity.Jobs;
[BurstCompile]
public struct SquareJob : IJobFor
{
[ReadOnly] public NativeArray<int> input;
[WriteOnly] public NativeArray<int> output;
public void Execute(int i)
{
output[i] = input[i] * input[i];
}
}
Schedule the job from the main thread:
handle = new SquareJob
{
input = input,
output = output
}.ScheduleParallel(input.Length, 64, default);
You should schedule it in Updatedo other work, then Complete in LateUpdate. If you call Completeright after scheduling, the main thread will wait again and the benefit of multithreading drops sharply.
The most important point is [BurstCompile]:
- With Burst: the job can run on a worker thread.
- Without Burst: the Web treats it as ordinary C## and runs it on the main thread.
Task.Rundo not get to “piggyback” on this capability.
What is needed for Burst Jobs to run multithreaded on the Web?
If one of the following conditions is missing, the Web cannot be considered to have worker threads:
- Use Unity 6.4+.
- Burst package 1.8.26+.
- Job has
[BurstCompile]. - Enable Enable Native C/C++ Multithreading in Web Player Settings. The name is a bit misleading: in Unity 6.4, this option enables both native threads and Burst Job threads.
- Host in a secure context, usually HTTPS.
- Server returns the required headers
COOP,COEP,CORP; the browser supportsSharedArrayBuffer.
Because the configuration is in both Unity and the server, being able to run in the Editor does not prove that the deployed build will run with multithreading.
What if 6.3 Web
or code that cannot use Burst?
async Awaitable<int> CalculateInChunks(int[] data)
{
int total = 0;
for (int i = 0; i < data.Length; i++)
{
total += Process(data[i]);
if ((i + 1) % 500 == 0)
await Awaitable.NextFrameAsync();
}
return total;
}
Split the work across multiple frames: This way helps the tab avoid freezing, but itdoes not run faster
. One person still does all the work, only resting between each turn so Unity can render the frame in time. async That is also why
awaitdoes not mean multithreading:- used to wait for a task to complete.
NextFrameAsyncCoroutine / - used to spread work across multiple frames. + Job CPU Burst is the way to take advantage of multiple 6.4.
core on the Web
- So which approach should you choose? APIDownload a file, call , load scene: AsyncOperation use Awaitable,
- CPU or Coroutine. heavy on Mobile: + prioritize the Job System# Burst; background threads are suitable for independent C
- CPU data blocks. 6.4+: heavy on Web
- use Burst Job if it meets the deployment conditions. 6.3 Web or logic that cannot use Burst:
- reduce workload, cache, split across multiple frames, or move the appropriate calculations to the server. Modify Unity objects:
- return to the main thread. Always profile on a real build
and a real browser. Easy-to-remember rule: Coroutine/Awaitable. If you need to wait, use async. If you need to spread load across multiple frames, use CPU If you need to take advantage of multiple + core, use Jobs and Burst — but check the version and platform.