The await
operator suspends execution of the enclosing async method, which allows the calling thread to perform other work while waiting. When the awaited Task
or Awaitable
completes, the asynchronous code needs to resume and continue its execution from the point it was suspended. How asynchronous code resumes can have important effects on the function and performance of your application.
Information about the state code was in when it began awaiting is referred to as the synchronization context. The .NET platform provides the SynchronizationContext
class for capturing this type of information. Task
continuations run in the synchronization context from which the asynchronous method was called, or through the thread pool if no synchronization context was set.
Most Unity APIs aren’t thread-safe and can only be called from the main thread. For this reason, Unity overwrites the default SynchronizationContext
with a custom UnitySynchronizationContext
to ensure all .NET Task
continuations in both Edit mode and Play mode run on the main thread by default. If you call a Task
-returning method from the Unity main thread, the continuation is posted to the UnitySynchronizationContext
and runs on the next frame Update
tick on the main thread. If you call it from a background thread, it completes on a thread pool thread.
Capturing a synchronization context increases the performance overhead of your application and waiting for the next frame Update to resume on the main thread introduces latency at scale. You can avoid both these issues by using Awaitable
instead.
Unless documented otherwise, all Awaitable
instances returned by Unity APIs, as well as any user defined async Awaitable
returning methods, have the following continuation scheduling behaviour:
ThreadPool
thread.The notable exceptions to that are:
Awaitable.MainThreadAsync
: continuation happens on the main thread.Awaitable.BackgroundThreadAsync
: continuation happens on a background thread.The effect of Awaitable.MainThreadAsync
and Awaitable.BackgroundThreadAsync
are local to the current method only, for example:
private async Awaitable<float> DoHeavyComputationInBackgroundAsync()
{
await Awaitable.BackgroundThreadAsync();
// here we are on a background thread
// do some heavy math here
return 42; // note: we don't need to explicitly get back to the main thread here, depending on the caller thread, DoHeavyComputationInBackgroundAsync will automatically complete on the correct one.
}
public async Awaitable Start()
{
var computationResult = await DoHeavyComputationInBackgroundAsync();
// although DoHeavyComputationInBackgroundAsync() internally switches to a background thread to avoid blocking,
// because we await it from the main thread, we also resume execution on the main thread and can safely call "main thread only APIs" such as LoadSceneAsync()
await SceneManager.LoadSceneAsync("my-scene"); // this will succeed as we resumed on main thread
}
Note: Unity doesn’t automatically stop code running in the background when you exit Play mode. To cancel a background operation on exiting Play mode, use Application.exitCancellationToken
.
It’s most efficient to call await Awaitable.MainThreadAsync()
from the main thread and await Awaitable.BackgroundThreadAsync()
from a background thread because in each case the code resumes immediately on completion. If you switch back to the main thread from a background thread with MainThreadAsync
, your code can’t resume until the next frame update on the main thread.
If you call a Task
-returning API from the main thread and it doesn’t complete synchronously, you’ll need to wait at least for the next Update
tick (33ms at 30fps) for the continuation to run. If network latency is a concern, it’s recommended to do this off the main thread and use custom logic to synchronize between the main thread and networkingThe Unity system that enables multiplayer gaming across a computer network. More info
See in Glossary tasks.
In development buildsA development build includes debug symbols and enables the Profiler. More info
See in Glossary, Unity displays the following error message if you try to use Unity APIs in multithreaded code:
UnityException: Internal_CreateGameObject can only be called from the main thread.
Constructors and field initializers will be executed from the loading thread when loading a scene.
Don't use this function in the constructor or field initializers, instead move initialization code to the Awake or Start function.
Important: For performance reasons, Unity doesn’t check for multithreaded behavior in non-development builds and doesn’t display this error in live builds. While Unity doesn’t prevent execution of multithreaded code in these contexts, crashes and other unpredictable errors are likely if you do use multiple threads. Instead of using your own multithreading, it’s safer to use Unity’s job system. The job system uses multiple threads safely to execute jobs in parallel and achieve the performance benefits of multithreading. For more information, refer to Job system overview.
Unity’s Awaitable
class is better suited to the following scenarios than the job system:
However, it’s not recommended for shorter-lived operations such as parallelizing computationally-intensive algorithms. To get the most of multi-core CPUs and parallelize your algorithms, use the job system instead.
AwaitableCompletionSource
and AwaitableCompletionSource<T>
allow creation of Awaitable
instances where completion is raised from user code. For example, this can be used to implement user prompts without having to implement a state machine to wait for the user interaction to finish:
public class UserNamePrompt : MonoBehavior
{
TextField _userNameTextField;
AwaitableCompletionSource<string> _completionSource = new AwaitableCompletionSource<string>();
public void Start()
{
var rootVisual = GetComponent<UIDocument>().rootVisualElement;
var userNameField = rootVisual.Q<TextField>("userNameField");
rootVisual.Q<Button>("OkButton").clicked += ()=>{
_completionSource.SetResult(userNameField.text);
}
}
public Awaitable<string> WaitForUsernameAsync() => _completionSource.Awaitable;
}
...
public class HighScoreRanks : MonoBehavior
{
...
public async Awaitable ReportCurrentUserScoreAsync(int score)
{
_userNameOverlayGameObject.SetActive(true);
var prompt = _userNameOverlayGameObject.GetComponent<UserNamePrompt>();
var userName = await prompt.WaitForUsernameAsync();
_userNameOverlayGameObject.SetActive(false);
await SomeAPICall(userName, score);
}
}
Did you find this page useful? Please give it a rating:
Thanks for rating this page!
What kind of problem would you like to report?
Thanks for letting us know! This page has been marked for review based on your feedback.
If you have time, you can provide more information to help us fix the problem faster.
Provide more information
You've told us this page needs code samples. If you'd like to help us further, you could provide a code sample, or tell us about what kind of code sample you'd like to see:
You've told us there are code samples on this page which don't work. If you know how to fix it, or have something better we could use instead, please let us know:
You've told us there is information missing from this page. Please tell us more about what's missing:
You've told us there is incorrect information on this page. If you know what we should change to make it correct, please tell us:
You've told us this page has unclear or confusing information. Please tell us more about what you found unclear or confusing, or let us know how we could make it clearer:
You've told us there is a spelling or grammar error on this page. Please tell us what's wrong:
You've told us this page has a problem. Please tell us more about what's wrong:
Thank you for helping to make the Unity documentation better!
Your feedback has been submitted as a ticket for our documentation team to review.
We are not able to reply to every ticket submitted.
When you visit any website, it may store or retrieve information on your browser, mostly in the form of cookies. This information might be about you, your preferences or your device and is mostly used to make the site work as you expect it to. The information does not usually directly identify you, but it can give you a more personalized web experience. Because we respect your right to privacy, you can choose not to allow some types of cookies. Click on the different category headings to find out more and change our default settings. However, blocking some types of cookies may impact your experience of the site and the services we are able to offer.
More information
These cookies enable the website to provide enhanced functionality and personalisation. They may be set by us or by third party providers whose services we have added to our pages. If you do not allow these cookies then some or all of these services may not function properly.
These cookies allow us to count visits and traffic sources so we can measure and improve the performance of our site. They help us to know which pages are the most and least popular and see how visitors move around the site. All information these cookies collect is aggregated and therefore anonymous. If you do not allow these cookies we will not know when you have visited our site, and will not be able to monitor its performance.
These cookies may be set through our site by our advertising partners. They may be used by those companies to build a profile of your interests and show you relevant adverts on other sites. They do not store directly personal information, but are based on uniquely identifying your browser and internet device. If you do not allow these cookies, you will experience less targeted advertising. Some 3rd party video providers do not allow video views without targeting cookies. If you are experiencing difficulty viewing a video, you will need to set your cookie preferences for targeting to yes if you wish to view videos from these providers. Unity does not control this.
These cookies are necessary for the website to function and cannot be switched off in our systems. They are usually only set in response to actions made by you which amount to a request for services, such as setting your privacy preferences, logging in or filling in forms. You can set your browser to block or alert you about these cookies, but some parts of the site will not then work. These cookies do not store any personally identifiable information.