Incomputer programming, theasync/await pattern is a syntactic feature of manyprogramming languages that allows anasynchronous,non-blockingfunction to be structured in a way similar to an ordinary synchronous function. It is semantically related to the concept of acoroutine and is often implemented using similar techniques, and is primarily intended to provide opportunities for the program to execute other code while waiting for a long-running, asynchronous task to complete, usually represented bypromises or similardata structures. The feature is found inC#,[1]: 10 C++,Python,F#,Hack,Julia,Dart,Kotlin,Rust,[2]Nim,[3]JavaScript, andSwift.[4]
F# added asynchronous workflows with await points in version 2.0 in 2007.[5] This influenced the async/await mechanism added to C#.[6]
Microsoft first released a version of C# with async/await in the Async CTP (2011). It was later officially released in C# 5 (2012).[7][1]: 10
Haskell lead developerSimon Marlow created the async package in 2012.[8]
Python added support for async/await with version 3.5 in 2015[9] adding 2 newkeywords,async andawait.
TypeScript added support for async/await with version 1.7 in 2015.[10]
JavaScript added support for async/await in 2017 as part ofECMAScript 2017 JavaScript edition.
Rust added support for async/await with version 1.39.0 in 2019 using theasync keyword and the.await postfix operator, both introduced in the 2018 edition of the language.[11]
C++ added support for async/await withversion 20 in 2020 with 3 new keywordsco_return,co_await,co_yield.
Swift added support for async/await withversion 5.5 in 2021, adding 2 new keywordsasync andawait. This was released alongside a concrete implementation of theActor model with theactor keyword[12] which uses async/await to mediate access to each actor from outside.
TheC# function below, which downloads a resource from aURI and returns the resource's length, uses this async/await pattern:
publicasyncTask<int>FindSizeOfPageAsync(Uriuri){HttpClientclient=new();byte[]data=awaitclient.GetByteArrayAsync(uri);returndata.Length;}
async keyword indicates to C# that the method is asynchronous, meaning that it may use an arbitrary number ofawait expressions and will bind the result to apromise.[1]: 165–168 Task<T>, is C#'s analogue to the concept of a promise, and here is indicated to have a result value of typeint.new HttpClient().GetByteArrayAsync(uri),[13]: 189–190, 344 [1]: 882 which is another asynchronous method returning aTask<byte[]>. Because this method is asynchronous, it will not download the entire batch of data before returning. Instead, it will begin the download process using a non-blocking mechanism (such as abackground thread), and immediately return an unresolved, unrejectedTask<byte[]> to this function.await keyword attached to theTask, this function will immediately proceed to return aTask<int> to its caller, who may then continue on with other processing as needed.GetByteArrayAsync() finishes its download, it will resolve theTask it returned with the downloaded data. This will trigger acallback and causeFindPageSizeAsync() to continue execution by assigning that value todata.data.Length, a simpleinteger indicating the length of the array. Thecompiler re-interprets this as resolving theTask it returned earlier, triggering a callback in the method's caller to do something with that length value.A function using async/await can use as manyawait expressions as it wants, and each will be handled in the same way (though a promise will only be returned to the caller for the first await, while every other await will utilize internal callbacks). A function can also hold a promise object directly and do other processing first (including starting other asynchronous tasks), delaying awaiting the promise until its result is needed. Functions with promises also have promise aggregation methods that allow the program to await multiple promises at once or in some special pattern (such as C#'sTask.WhenAll(),[1]: 174–175 [13]: 664–665 which returns a valuelessTask that resolves when all of the tasks in the arguments have resolved). Many promise types also have additional features beyond what the async/await pattern normally uses, such as being able to set up more than one result callback or inspect the progress of an especially long-running task.
In the particular case of C#, and in many other languages with this language feature, the async/await pattern is not a core part of the language's runtime, but is instead implemented withlambdas orcontinuations at compile time. For instance, the C# compiler would likely translate the above code to something like the following before translating it to its ILbytecode format:
publicTask<int>FindSizeOfPageAsync(Uriuri){HttpClientclient=new();Task<byte[]>dataTask=client.GetByteArrayAsync(uri);Task<int>afterDataTask=dataTask.ContinueWith((originalTask)=>{returnoriginalTask.Result.Length;});returnafterDataTask;}
Because of this, if an interface method needs to return a promise object, but itself does not requireawait in the body to wait on any asynchronous tasks, it does not need theasync modifier either and can instead return a promise object directly. For instance, a function might be able to provide a promise that immediately resolves to some result value (such as C#'sTask.FromResult()[13]: 656 ), or it may simply return another method's promise that happens to be the exact promise needed (such as when deferring to anoverload).
One important caveat of this functionality, however, is that while the code resembles traditional blocking code, the code is actually non-blocking and potentially multithreaded, meaning that many intervening events may occur while waiting for the promise targeted by anawait to resolve. For instance, the following code, while always succeeding in a blocking model withoutawait, may experience intervening events during theawait and may thus find shared state changed out from under it:
stringname=state.name;HttpClientclient=new();byte[]data=awaitclient.GetByteArrayAsync(uri);// Potential failure, as value of state.a may have been changed// by the handler of potentially intervening event.Debug.Assert(name==state.name);returndata.Length;
TheC language does not support await/async. Some coroutine libraries such as s_task[14] simulate the keywords await/async with macros.
#include<stdio.h>#include"s_task.h"constexprintSTACK_SIZE=64*1024/sizeof(int);// define stack memory for tasksintg_stack_main[STACK_SIZE];intg_stack0[STACK_SIZE];intg_stack1[STACK_SIZE];voidsub_task(__async__,void*arg){intn=(int)(size_t)arg;for(inti=0;i<5;++i){printf("task %d, delay seconds = %d, i = %d\n",n,n,i);s_task_msleep(__await__,n*1000);// s_task_yield(__await__);}}voidmain_task(__async__,void*arg){// create two sub-taskss_task_create(g_stack0,sizeof(g_stack0),sub_task,(void*)1);s_task_create(g_stack1,sizeof(g_stack1),sub_task,(void*)2);for(inti=0;i<4;++i){printf("task_main arg = %p, i = %d\n",arg,i);s_task_yield(__await__);}// wait for the sub-tasks for exits_task_join(__await__,g_stack0);s_task_join(__await__,g_stack1);}intmain(intargc,char*argv[]){s_task_init_system();// create the main tasks_task_create(g_stack_main,sizeof(g_stack_main),main_task,(void*)(size_t)argc);s_task_join(__await__,g_stack_main);printf("all task is over\n");return0;}
In C++, await (namedco_await in C++ to emphasise its context in coroutines) has been officially merged intoversion 20.[15] Support for it, coroutines, and the keywords such asco_await are available inGCC andMSVC compilers whileClang has partial support.
It is worth noting thatstd::promise andstd::future, although it would seem that they would be awaitable objects, implement none of the machinery required to be returned from coroutines and be awaited usingco_await. Programmers must implement a number of public member functions, such asawait_ready,await_suspend, andawait_resume on the return type in order for the type to be awaited on. Details can be found on cppreference.[16]
Suppose there is some classAwaitableTask<T>, it must implementoperator co_await() to be used in coroutines.
importstd;importorg.wikipedia.util.AwaitableTask;usingorg::wikipedia::util::AwaitableTask;AwaitableTask<int>add(inta,intb){intc=a+b;co_returnc;}AwaitableTask<int>test(){intret=co_awaitadd(1,2);std::println("Return {}",ret);co_returnret;}intmain(){AwaitableTask<int>task=test();return0;}
In 2012, C# added the async/await pattern in C# with version 5.0, which Microsoft refers to as the task-based asynchronous pattern (TAP).[17] Async methods usually return eithervoid,Task,Task<T>,[13]: 35 [18]: 546–547 [1]: 22, 182 ValueTask orValueTask<T>.[13]: 651–652 [1]: 182–184 User code can define custom types that async methods can return through customasync method builders but this is an advanced and rare scenario.[19] Async methods that returnvoid are intended forevent handlers; in most cases where a synchronous method would returnvoid, returningTask instead is recommended, as it allows for more intuitive exception handling.[20]
Methods that make use ofawait must be declared with theasync keyword. In methods that have a return value of typeTask<T>, methods declared withasync must have areturn statement of type assignable toT instead ofTask<T>; the compiler wraps the value in theTask<T> generic. It is also possible toawait methods that have a return type ofTask orTask<T> that are declared withoutasync.
The following async method downloads data from a URL usingawait. Because this method issues a task for each URI before requiring completion with theawait keyword, the resources can load at the same time instead of waiting for the last resource to finish before starting to load the next.
publicasyncTask<int>SumPageSizesAsync(IEnumerable<Uri>uris){HttpClientclient=new();inttotal=0;List<Task<byte[]>>loadUriTasks=new();foreach(Uriuriinuris){byte[]loadUriTask=client.GetByteArrayAsync(uri);loadUriTasks.Add(loadUriTask);}foreach(Task<byte[]>>loadUriTaskinloadUriTasks){statusText.Text=$"Found {total} bytes ...";byte[]resourceAsBytes=awaitloadUriTask;total+=resourceAsBytes.Length;}statusText.Text=$"Found {total} bytes total";returntotal;}
In 2007, F# added asynchronous workflows with version 2.0.[21] The asynchronous workflows are implemented as CE (computation expressions). They can be defined without specifying any special context (likeasync in C#).F# asynchronous workflows append a bang (!) to keywords to start asynchronous tasks.
The following async function downloads data from an URL using an asynchronous workflow:
letasyncSumPageSizes(uris:#seq<Uri>):Async<int>=async{usehttpClient=newHttpClient()let!pages=uris|>Seq.map(httpClient.GetStringAsync>>Async.AwaitTask)|>Async.Parallelreturnpages|>Seq.fold(funaccumulatorcurrent->current.Length+accumulator)0}
Java does not haveasync andawait keywords in the language, however it can be emulated using thejava.util.concurrent package, such as the classCompletableFuture (introduced in Java 8). Asynchronous programming is later improved in Java 21 with the introduction of virtual threads and structured task scopes.
packageorg.wikipedia.examples;importjava.util.concurrent.CompletableFuture;importjava.util.concurrent.ExecutionException;importjava.util.concurrent.ExecutorService;importjava.util.concurrent.Executors;importjava.util.concurrent.Future;import staticjava.util.concurrent.StructuredTaskScope.ShutdownOnFailure;import staticjava.util.concurrent.StructuredTaskScope.Subtask;publicclassAsyncExample{publicStringfetchData(){// Simulate a time-consuming operation (e.g., network request, database query)try{Thread.sleep(2000);}catch(InterruptedExceptione){Thread.currentThread().interrupt();}return"Data from remote source";}publicCompletableFuture<String>fetchDataAsync(){returnCompletableFuture.supplyAsync(()->fetchData());}publicstaticvoidmain(String[]args)throwsExecutionException,InterruptedException{AsyncExampleexample=newAsyncExample();// Using CompletableFuture (Java 8)System.out.println("Starting asynchronous operation...");CompletableFuture<String>future=example.fetchDataAsync();System.out.println("Doing other work...");// Wait for the result (similar to 'await')Stringresult=future.get();System.out.printf("Received result: %s%n",result);// Using Virtual Threads (Java 21):ExecutorServiceextor=Executors.newVirtualThreadPerTaskExecutor();System.out.println("Starting virtual thread operation...");Future<String>fut=extor.submit(()->{returnexample.fetchData();});System.out.println("Doing other work...");Stringresult=future.get();System.out.printf("Received result: %s%n",result);extor.shutdown();// Using StructuredTaskScope (Java 21)try(ShutdownOnFailurescope=newShutdownOnFailure()){Subtask<String>dataTask=scope.fork(example::fetchData);System.out.println("Doing other work...");scope.join();// wait for all tasksscope.throwIfFailed();// propagate if any exceptionsStringresult=future.get();System.out.printf("Received result: %s%n",result);}}}
The await operator in JavaScript (and TypeScript) can only be used from inside an async function or at the top level of amodule. If the parameter is apromise, execution of the async function will resume when the promise is resolved (unless the promise is rejected, in which case an error will be thrown that can be handled with normal JavaScriptexception handling). If the parameter is not a promise, the parameter itself will be returned immediately.[22]
Many libraries provide promise objects that can also be used with await, as long as they match the specification for native JavaScript promises. However, promises from thejQuery library were not Promises/A+ compatible until jQuery 3.0.[23]
Below is an example (modified from this[24] article):
interfaceDBResponse{id:string;rev?:string;ok?:boolean;}interfaceDocument{_id:string;_rev?:string;[key:string]:any;}interfaceDatabase{post(doc:object):Promise<DBResponse>;get(id:string):Promise<Document>;}declareconstdb:Database;asyncfunctioncreateNewDoc():Promise<Document>{constresponse:DBResponse=awaitdb.post({});constdoc:Document=awaitdb.get(response.id);returndoc;}asyncfunctionmain():Promise<void>{try{constdoc:Document=awaitcreateNewDoc();console.log(doc);}catch(err:Error){console.error("Error creating or fetching document:",err);}}main();
Node.js version 8 includes a utility that enables using the standard library callback-based methods as promises.[25]
The Future::AsyncAwait[26] module was the subject of a Perl Foundation grant in September 2018.[27]
Python 3.5 (2015)[28] has added support for async/await as described in PEP 492 (written and implemented byYury Selivanov).[29]
importasyncioasyncdefmain()->None:print("hello")awaitasyncio.sleep(1)print("world")if__name__=="__main__":asyncio.run(main())
On November 7, 2019, async/await was released on the stable version of Rust.[30] Async functions in Rustdesugar to plain functions that return values that implement the Future trait. Currently they are implemented with afinite-state machine.[31]
// In the crate's Cargo.toml, we need `futures = "0.3.0"` in the dependencies section,// so we can use the futures crateexterncratefutures;// There is no executor currently in the `std` library.usestd::future::Future;// This desugars to something like// `fn async_add_one(num: u32) -> impl Future<Output = u32>`asyncfnasync_add_one(num:u32)->u32{num+1}asyncfnexample_task()->implFuture<Output=()>{letnumber=async_add_one(5).await;println!("5 + 1 = {}",number);}fnmain(){// Creating the Future does not start the execution.letfuture=example_task();// The `Future` only executes when we actually poll it, unlike JavaScript.futures::executor::block_on(future);}
Swift 5.5 (2021)[32] added support for async/await as described in SE-0296.[33]
funcgetNumber()asyncthrows->Int{tryawaitTask.sleep(nanoseconds:1_000_000_000)return42}Task{letfirst=tryawaitgetNumber()letsecond=tryawaitgetNumber()print(first+second)}
The async/await pattern is especially attractive to language designers of languages that do not have or control their own runtime, as async/await can be implemented solely as a transformation to astate machine in the compiler.[34]
Supporters claim that asynchronous, non-blocking code can be written with async/await that looks almost like traditional synchronous, blocking code. In particular, it has been argued that await is the best way of writing asynchronous code inmessage-passing programs; in particular, being close to blocking code, readability and the minimal amount ofboilerplate code were cited as await benefits.[35] As a result, async/await makes it easier for most programmers to reason about their programs, and await tends to promote better, more robust non-blocking code in applications that require it.[dubious –discuss]
Critics of async/await note that the pattern tends to cause surrounding code to be asynchronous too; and that its contagious nature splits languages' library ecosystems between synchronous and asynchronous libraries and APIs, an issue often referred to as "function coloring".[36] Alternatives to async/await that do not suffer from this issue are called "colorless". Examples of colorless designs include Go'sgoroutines and Java'svirtual threads.[37]
{{cite web}}: CS1 maint: archived copy as title (link)