huhx / flutter_oss_aliyun

阿里云oss sdk的flutter版本
MIT License
61 stars 23 forks source link

Only await on Future #36

Closed kj415j45 closed 1 year ago

kj415j45 commented 1 year ago

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

 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: image

JS

Compile: dart compile js -O4 test.dart Source:

<head>
    <script src="out.js"></script>
</head>

Result: image

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:

  1. await on FutureOr lead to some unnecessary runtime type check, which makes the code slower than await conditionally.
  2. 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.
kj415j45 commented 1 year ago

Close due to found some mistakes in experiment, will reopen after fixing those.