Question

I'm learning Dart's Future, and have read some articles about the Future.

It says Dart is single-thread, and we can use Future to make some expensive functions run later, e.g. reading files.

Suppose reading a file will cost 10 seconds, and I have 3 files to read.

My dart code:

main() {
  readFile("aaa.txt");
  readFile("bbb.txt");
  readFile("ccc.txt");
  print("Will print the content of the files later");
}

readFile(String filename) {
  File file = new File(filename);
  file.readAsString().then((content) {
    print("File content:\n");
    print(content);
  });
}

Since reading a file will cost 10 seconds, so the above code will cost at least 30 seconds, right? Using futures to read files just to make the expensive tasks run later one by one, without blocking current code, but won't reduce the total cost?

If in java, I can make a thread pool, and make 3 future tasks running in parallel, the total cost will be between 10 and 20 seconds.

Is it possible to do the same in Dart? Is using Dart's isolate the only solution?

Was it helpful?

Solution

I would expect that this could take 10 seconds, as it will start three reads, each of which will queue an callback to the "then" function when the read is complete. It is entirely possible that the three files will load in parallel and all complete after 10 seconds. The callbacks will be called on the main thread sequentially though.

Although the user code in dart is single threaded (assuming you don't use isolates or web workers), nothing says that the implementation can't create threads or use the operating system's asynchronous loading to perform tasks in parallel as long as the future's run sequentially in the main thread.

OTHER TIPS

That's correct. If you start an new async path with new Timer(), new Future(), or scheduleMicrotask() it will be scheduled for later execution.

When one of your async paths is waiting for a network request or the file system returning data, another async path may jump in and run in the meantime. So you might get a runtime less than 30 seconds, but you can't reduce runtime by adding a CPU. I have to admit, that I don't know details about when scheduling takes place and how it works exactly.

Dart has no threads, so if you want to run code in parallel you need isolates.

Almost 30 seconds.

I had just run the code with dart 2.16.2, and the result is almost 30 seconds.

here is my code:

import 'dart:async';
import 'dart:convert';
import 'dart:io';

import 'dart:isolate';

main() async {
  print('main start');

  printCurrentTime("main before all future");
  Future(() => readFile(0));
  Future(() => readFile(1));
  Future(() => readFile(2));
  Future(() {
    printCurrentTime("future last");
  });

  print('main end');
  printCurrentTime("main");
}

printCurrentTime(String name) {
  print("$name ${DateTime.now().millisecondsSinceEpoch}");
}

readFile(number) {
  print("start read file $number");
  var watch = Stopwatch();
  watch.start();
  var filename = r"path/to/file";
  File file = File(filename);
  file.readAsBytes().then((content) {
    printCurrentTime("\nfuture#$number start");
    print("File $number content:");
    print(content.toString().length);
    printCurrentTime("future#$number finish");
    print("finish read file $number");
  });
}

And here is the result:

main start
main before all future 1652964314276
main end
main 1652964314278
// all the event queue start to run
start read file 0
start read file 1
start read file 2
future last 1652964314290

// the dart system read file parallelly, after finish read file
// they put the future to the event queue, and dart start running all
// those event task one by one:
future#0 start 1652964314343
File 0 content:
241398625
future#0 finish 1652964317457
finish read file 0

future#1 start 1652964317457
File 1 content:
241398625
future#1 finish 1652964320470
finish read file 1

future#2 start 1652964320471
File 2 content:
241398625
future#2 finish 1652964323403
finish read file 2

As we can see:

file.readAsBytes() take about 53ms (or 100ms sometime during my test)

content.toString() take about 3s or more

So we can come to this conclusion: file.readAsBytes() all run in the other thread parallelly, and the value the return Future<Uint8List> is added to the Event Task dequeue which is run synchronously, that's why we can see the future#1 start... print one by one.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top