问题
I'm currently learning Dart, but this is also applicable to what's going on in the JavaScript world right now, and it seems like C# also uses the same pattern.
In Dart, any function that uses await
must itself be labeled asynchronous through async
as follows:
import "dart:html";
main() async {
var context = querySelector("canvas").context2D;
var running = true;
while (running) {
var time = await window.animationFrame;
...
}
}
This does not make sense to me. If a function is waiting on an asynchronous function to complete, is it not then considered blocking? Why do JS and Dart require it to be labeled asynchronous? Would it not be the opposite?
To me it would make far more sense if the calling function must use the async
keyword if it calls any function that also includes it in its definition. In this pattern, await
would be used to convert asynchronous functions to synchronous ones.
This way would also avoid duplicate functions, since right now, libraries seem to always have func()
and funcSync()
or funcAsync()
.
回答1:
The basic semantics of async
/await
are the same across F#, VB, C#, Python, Dart, Hack, and JavaScript. So I think this question has sufficient answers from other languages. But since it has been reopened...
If a function is waiting on an asynchronous function to complete, is it not then considered blocking?
No. Think about it this way:
- "asynchronous" means "does not block the calling thread".
- "synchronous" means "blocks the calling thread".
In an asynchronous method/function, the method/function can be paused at the await
points, but it does not block the calling thread while it is paused. The function runs serially (one statement at a time), but asynchronously (without blocking the calling thread).
To me it would make far more sense if the calling function must use the async keyword if it calls any function that also includes it in its definition.
That's how it already works... await
consumes promise/future/task-returning methods/functions, and async
marks a method/function as capable of using await
.
This way would also avoid duplicate functions
This is not possible with historically-blocking imperative languages. A method/function either blocks the calling thread until it is complete, or it does not. It is either synchronous or asynchronous.
There are some interesting alternative approaches to async methods/functions, though:
Go is not historically blocking; you can think of it as a language where every method/function is potentially asynchronous; doing this in any other runtime would be disastrous, but Go avoids those problems by implementing a strict goroutine system with message passing - no shared memory or threads allowed.
Another example are pure functional languages, where Future is just another monad and requires no special compiler support for async
/await
keywords.
回答2:
In Dart async
indicates that the code containing await
needs to be rewritten.
async
/await
is just syntactic sugar for the Future.then()
base API, and the code is rewritten to this canonical Future
based form, before it is compiled and executed.
Therefore await
doesn't make code blocking.
There are also other supported markers like *sync
and *async
for generators.
See also - Dart async/await internals - https://www.dartlang.org/articles/language/await-async
回答3:
I'm not sure what your question has to do with C# but await
is a most unfortunate keyword choice in C#. await
is more understandable if you read it as resume after
or even yield then resume after
. When execution encounters await
, it suspends the current function, returning to its caller. Once the Task
being waited on is done, execution resumes after the await
when the caller needs the result (from an await
expression of its own).
回答4:
This is a fundamental misunderstanding of what's going on "under-the-hood", I'm assuming the javascript async/await implementation mirrors (at least conceptually) that of the .NET world (which originated in F#).
Essentially:
- A "unit of work" "token" of sorts (in C# a Task in JS a Promise) represents a completion of a task with an option of returning a value.
- An "asynchronous" method is marked with async, to indicate to the compiler/interpreter/runtime whatever, that this method will return said token, and will likely consume some as well.
- The thingamajig running it all, will (in C#'s case), rewrite the code on the sly to essentially do the following:
- Start async method
- Do standard normal code
- Encounter "token" providing method
- Call it, grab token
- Setup a place the code can jump back to later
- Is the token complete? If so, carry on, If not, set a callback to have the runtime come back to this place when it does
In this expanded context, the keywords make sense:
- async(hronous) - A method that does some task that can take an indeterminate amount of time, that can be waited upon.
- await - Indicates that instead of just grabbing the token from the async method and doing nothing with it, that you actually want to set up all this ceremony around listening out for when the work is done, and carrying on afterwards.
tl;dr
Just think of async and await as invisible callbacks, async indicates when something can be listened out for, and await is what actually does the listening.
来源:https://stackoverflow.com/questions/44894691/why-await-requires-async-in-function-definition