In #32, I suggested to use FutureOr for better compatibility. Recently I made an experiment about it and found that current implements may impact performance here. That's the reason of this PR.
Benchmark
Environment
screenfetch -n
OS: 64bit Mac OS X 12.6.2 21G320
Kernel: x86_64 Darwin 21.6.0
CPU: Intel Core i5-5250U @ 1.60GHz
RAM: 3327MiB / 8192MiB
Dart SDK version: 2.19.3 (stable) (Tue Feb 28 15:52:19 2023 +0000) on "macos_x64"
Chrome version: 111.0.5563.110 (x86_64)
Code
import 'dart:async';
import 'package:benchmarking/benchmarking.dart';
Future<void> main() async {
const testTime = 10000;
(await asyncBenchmark('Await conditional on Future', () async {
var count = 0;
while (count++ != testTime) {
await awaitConditional(foo);
}
}))
.report();
(await asyncBenchmark('Await conditional on int', () async {
var count = 0;
while (count++ != testTime) {
await awaitConditional(bar);
}
}))
.report();
(await asyncBenchmark('Await anyway on Future', () async {
var count = 0;
while (count++ != testTime) {
await awaitAnyway(foo);
}
}))
.report();
(await asyncBenchmark('Await anyway on int', () async {
var count = 0;
while (count++ != testTime) {
await awaitAnyway(bar);
}
}))
.report();
}
Future<int> foo() async {
return 1;
}
int bar() {
return 1;
}
int? x;
Future<int> awaitAnyway(FutureOr<int> Function() func) async {
x = await func();
return x!;
}
Future<int> awaitConditional(FutureOr<int> Function() func) async {
if (func is Future Function()) {
x = await func();
} else {
x = func() as int;
}
return x!;
}
Result
Native
Compile: dart compile exe test.dart && ./test.exe
Result:
JS
Compile: dart compile js -O4 test.dart
Source:
<head>
<script src="out.js"></script>
</head>
Result:
Conclude & Analyze
Await conditionally is faster than directly await on FutureOr. It's faster when the return type of func is Future and much more faster when the return type of func is non-Future.
I suspect that:
await on FutureOr lead to some unnecessary runtime type check, which makes the code slower than await conditionally.
Beyond that, await on non-Future expression will be transform into await Future.value(expression) at compile time. And you may find some clue in -O1 compiled js. That could explain why it has a much more slower execution time.
Did not run any tests but it should works.
Abstract
In #32, I suggested to use
FutureOr
for better compatibility. Recently I made an experiment about it and found that current implements may impact performance here. That's the reason of this PR.Benchmark
Environment
screenfetch -n
Dart SDK version:
2.19.3 (stable) (Tue Feb 28 15:52:19 2023 +0000) on "macos_x64"
Chrome version:111.0.5563.110 (x86_64)
Code
Result
Native
Compile:
dart compile exe test.dart && ./test.exe
Result:
JS
Compile:
dart compile js -O4 test.dart
Source:Result:
Conclude & Analyze
Await conditionally is faster than directly await on
FutureOr
. It's faster when the return type offunc
isFuture
and much more faster when the return type offunc
is non-Future
.I suspect that:
await
onFutureOr
lead to some unnecessary runtime type check, which makes the code slower than await conditionally.await
on non-Future
expression will be transform intoawait Future.value(expression)
at compile time. And you may find some clue in-O1
compiled js. That could explain why it has a much more slower execution time.