-
Notifications
You must be signed in to change notification settings - Fork 1.7k
the performance of async and await syntax are quite slow #29189
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
btw, the deferred load library can use the same trick. For example, (in our workaround)
The result will be: |
If you just return a Now, comparing different asynchronous implementations is much more interesting :) It's not surprising that latency suffers when you go to an foo() => new Future.value(42); and bar() async => 42; is that the latter delays execution of the body until a later microtask. That latency is unavoidable as long as the language semantics requires that delay. If you look at this dartpad, then dart2js doesn't really get delayed by It can't explain all of the difference for the VM, though, it's |
Yes, I know that comparing Sync and Async is not fair, but in the real life it happens that we have to design an API to serve two different implementations in Sync and Async ways and only expose one public API. |
I agree that everything should be faster, and we are definitely not fast enough at That said, hiding a synchronous operation behind an async API will always have a cost. We should just try to ensure that the cost is as minimal as possible, but it won't go away. |
FYI, AngularDart has requested a lint to remove all uses of |
@jumperchen, here is an example showing how you can use import 'dart:async';
abstract class SyncOrAsync<X> {
FutureOr<X> m(X x);
}
class Sync<X> implements SyncOrAsync<X> {
X m(X x) => x;
}
class Async<X> implements SyncOrAsync<X> {
Future<X> m(X x) async => x;
}
bool b = true; // Whatever.
main() async {
int result;
SyncOrAsync<int> o = b ? Sync<int>() : Async<int>();
FutureOr<int> x = o.m(42);
if (x is Future) {
result = await x;
} else {
result = x;
}
print(result);
} With PS: It is not uncommon to recommend that |
@matanlurey, I'd prefer if AngularDart would put pressure on everyone (who can do something about it) to make async/await run fast. ;-) |
@eernstg Yes, we had that already. (a fake future)
|
@jumperchen, a fake future is in fact exactly what you don't need: With |
@eernstg Yes, it could be but when we introduced the |
It's been done for years, but not been a priority for the language team (this isn't just a backend issue). The fact that you can write: func() async {
return await 5;
} ... and this isn't either (a) a compile-time error or (b) just semantic sugar for: func() {
return new Future.value(5);
} ... makes it really difficult to optimize. And that's not even getting into the complex cases. |
@jumperchen, I acknowledge that 300K lines of asynchronous code is a very powerful argument in favor of introducing a "fake future" and then making all that code run synchronously, essentially without editing any of it. It's cool that you made that work! However, I think you will still pay something for that approach (in addition to the obvious: that you're creating a lot of wrapper objects of type In particular, we can't let import 'dart:async';
var x = true;
f() async {
x = false;
}
main() async {
var fut = f();
while (x) {
await print(".");
}
} The point is that a compiler cannot be allowed to compile
So, given that your software needs to work on the actual values of the futures or This could be taken as a hint that there would be a real performance benefit in writing the code in a synchronous style, compared to the approach where synchronous execution is (mostly) achieved based on using I can understand that you may still prefer to use the fake futures because they allow you to avoid touching your code. But when this trade-off between explicitly synchronous computations (with some amount of code duplication) and fake-future based semi-synchronous computations (with complete reusability of the same code for asynchronous execution) can be made up front, it may be worthwhile to write some synchronous code as well. |
We certainly do have lots of code that relies on this today and it may be infeasible to refactor it. Is there a reason to think that code (ab)using await new Future.microtask():
print("."); |
Yes, that's been made an example many times. Honestly most users consider it a bug, however. I think @mraleph once suggested we just allow I could even see it possible to just allow a "naked" var i = 0;
while (true) {
await;
print('${i++}');
} ... instead of relying on I found reading the V8 team's performance overview of their problems with I recommend reading V8's performance overview on async/await (similar issues): |
(Of course if we compile |
@natebosch, surely we could lint away The other side of the same coin is that (I think) we should preserve the notion that "await will wait", because that makes it easier for developers to reason about the correctness of their programs (when they do need suspension-for-progress). If we weren't doing that then we could just allow the compiler to make
@matanlurey, that's a delicate balance. It is basically the same thing as saying that it is a bug to have side-effects in your program (at least whenever it uses asynchrony). There is no end to the beautiful and well-founded arguments that you can make for that position, but those arguments have been put forward for half a century and we still have side-effects, so maybe the convenience/comprehensibility trade-off is non-trivial. I think the main point is that it is important to be able to understand software precisely, no matter which paradigm it's written in. In this case that would be a strong argument for linting |
The performance of async/await in the Dart VM has been improved by a factor of 10x. The VM specific issue for that was #37668, which has been closed. It's unclear if this bug refers to async/await performance in general or in the Dart VM. Though I'll remove the If this was meant as a Dart VM bug only, I believe we can close it. |
Checking the benchmark I linked above, it seems that async/await is on par with directly written future code. Some of that is probably helped by us no longer being asynchronous on entry. |
Let's close this issue then. If there's other performance issues, please file a new bug. |
Scenario
Sometimes we design an API to allow the returned value to be a Future or a Sync, which depends on its logic, so we will declare the returned value to be a Future in the function/method syntax.
For example,
And then if the 'foo()' is called in a for loop for thousand� times, the async and await syntax will be the performance nightmare.
For example,
The result will be
An Idea
In our workaround, we implement a Sync class to extend the Future class, and by using the syntax of bar() to cheat the compiler, and it can speed up in the runtime.
For example,
So it could be an idea to make this trick in Dart VM.
The text was updated successfully, but these errors were encountered: