dart-lang / sdk

The Dart SDK, including the VM, JS and Wasm compilers, analysis, core libraries, and more.
https://dart.dev
BSD 3-Clause "New" or "Revised" License
10.22k stars 1.57k forks source link

Reading files asynchronously is 40% slower than reading them synchronously #19156

Open peter-ahe-google opened 10 years ago

peter-ahe-google commented 10 years ago

The async.dart program below is 40% slower than sync.dart:

==> sync.dart <== import 'dart:io';

main(List<String> arguments) {   Stopwatch sw = new Stopwatch()..start();   Map<String, String> sources = <String, String>{};   Uri testScheme = new Uri(scheme: 'org-dartlang-test');   for (String argument in arguments) {     Uri uri = testScheme.resolve(argument);     String source =         new File.fromUri(Uri.base.resolve(argument)).readAsStringSync();     sources['$uri'] = source;   }   sw.stop();   print(sw.elapsedMilliseconds); }

==> async.dart <== import 'dart:io';

import 'dart:async';

main(List<String> arguments) {   Stopwatch sw = new Stopwatch()..start();   Map<String, String> sources = <String, String>{};   Future<String> futures = new List<Future<String>>();   Uri testScheme = new Uri(scheme: 'org-dartlang-test');   for (String argument in arguments) {     Uri uri = testScheme.resolve(argument);     Future<String> future =         new File.fromUri(Uri.base.resolve(argument)).readAsString();     futures.add(future.then((String source) {       sources['$uri'] = future;     }));   }   Future.wait(futures).then((_) {     sw.stop();     print(sw.elapsedMilliseconds);   }); }

I've measured this at r36733. On my Mac which is a dual 3.06 GHz 6-Core Intel Xeon running OS X version 10.9.3 (mavericks).

I've run the test 10 times (after initial runs to ensure all files are cached) using:

for i in {1..10} ; do ./sdk/bin/dart -pp/ sync.dart tests/compiler/dart2js_extra/*.dart; done

for i in {1..10} ; do ./sdk/bin/dart -pp/ async.dart tests/compiler/dart2js_extra/*.dart; done

On average sync runs in 54.6 milliseconds (average deviation 0.48), and async runs in 75.1 milliseconds (average deviation 0.96). 75.1/54.6 is 138%.

peter-ahe-google commented 10 years ago

It was pointed out to me that perhaps I was starving my machine for CPUs. So I wrote a more sequential version:

import 'dart:io';

import 'dart:async';

main(List<String> arguments) {   Stopwatch sw = new Stopwatch()..start();   Map<String, String> sources = <String, String>{};   Future<String> futures = new List<Future<String>>();   Uri testScheme = new Uri(scheme: 'org-dartlang-test');   Future.forEach(arguments, (String argument) {     Uri uri = testScheme.resolve(argument);     Future<String> future =         new File.fromUri(Uri.base.resolve(argument)).readAsString();     return future.then((String source) {       sources['$uri'] = future;     });   }).then((_) {     sw.stop();     print(sw.elapsedMilliseconds);   }); }

On average this runs in 100.2 ms (average deviation 1.92) which is 184% of 54.6.

bkonyi commented 6 years ago

Just re-ran the code from above and it looks like we've regressed further (or things are just as bad as before and the differing numbers is due to HW configuration).

Sync Avg: 67.6 ms Async Ave: 149.3 ms

Difference: ~221%

simc commented 5 years ago

This is a real problem in some situations and there is no workaround afaik. Since dart has no multithreading, it is almost impossible to use the sync io for example in Flutter.

I hope this issue will be worked on some time soon :+1:

simc commented 4 years ago

@peter-ahe-google @bkonyi Any news on this issue?

DanMossa commented 1 year ago

I'm getting similar issues and I'm wondering if it's still preferred to use sync methods?

bkonyi commented 1 year ago

cc @aam

aam commented 1 year ago

Yeah, I think async infrastructure still carries rather noticeable amount of overhead, so equivalent sync operations are faster. Async allows for better concurrent workload management, but in absence of that no real reason to use that.

brianquinlan commented 1 year ago

To elaborate on what @aam said, there is significant overhead in async File operations:

  1. all async File operations involve sending the request and response though a port
  2. some async File operations

What if we modified the documentation like:

From:

Unless you have a specific reason for using the synchronous version of a method, prefer the asynchronous version to avoid blocking your program.

To:

The synchronous version of a method will always be more performant than the asynchronous version, sometimes significantly so. However, using the synchronous version of a method will block your program.