Dart programs run in a single isolate by default. Although Dart provides several comfortable asynchronous programming techniques like Futures and Streams Dart does not use multithreading features of modern processors by default.
This is a reasonable language design decision mainly due to problematic controllability of concurrency aspects (thread safety) in programming.
Let us assume we want to calculate the sum of the fibonacci numbers from 40 to 45
by applying the following function
fib (and of course the fibonacci function is here only a
placeholder for any computational intensive function of the real world)
we could do this in Dart like that (a very simple example of map/reduce):
This would prompt the following result on console.
The most computational intensive part of this operation is to apply several times the
map. And although
map is perfectly parallelizable in the shown case
Dart would not execute it in parallel due to the fact that every Dart program runs in a single
isolate (even if a Dart program runs on a processor being capable to process
more than one thread in parallel).
Nevertheless Dart is capable to run several computations in parallel using isolates. Isolates in Dart are isolated threads having no shared access to memory (so they can share no data). Isolates can only pass messages between each other. This rigid concept solves all relevant thread safety problems and that is why you need no
synchronized statement in Dart. Nevertheless spawning isolates capable to communicate with each other is unnecessary tricky in Dart. Diego Rocha has written a blog post about this complexity and states:
You have to spawn a new isolate, send it a
SendPortof your current isolate, listen to the
ReceivePortof your current isolate, then make the spawned isolate listen to its
ReceivePort, send messages requesting something and then responding those messages. If you try to run multiple isolates at the same time, it is even more troublesome as you don’t know from which isolate a message is coming from.
Using the worker package to parallelize map
By using Rochas Worker package the calculation of our fibonacci sum can be parallelized like that
and we will get the same result (but now computed in parallel).
Discussion of the worker solution
Nevertheless the solution is not like pragmatic programmers would prefer to parallelize the given problem. We had to define another class to execute a function in parallel. OK, Java programmers are used to create a class for everything but most programmers do not see the necessity for such things. Me either (but actual it is not possible to do it in another way, but we will come to this later).
Let us take our initial problem.
In fact we want to tell Dart to execute
vs.map((n) => fib(n)
in parallel. It would be cool, if we could write something like
vs.pmap((n) => fib(n))
and the method
pmap would do all the parallelization for us because that is in fact
what most programmers want to express.
Lovely programm please process all elements of
in parallel (and not in sequential order, which is what
This is called a parallel map and it works great on iterables. Parallel map
pmap might be typed like that:
pmap returns a
Future (it is executed asynchronously because it is parallel) of an
Iterable we have to rewrite our
initial problem a little bit.
From my point of view this would be the perfect solution for Dart providing a very pragmatic form of parallelization.
Why closures are not always cool
But this is not possible in Dart. Due to the fact that a closure can reference (and change) a variable state outside its scope it is not allowed to be passed between isolates. If we could we had all problems of thread safety again. So closures are no adequate solution for our problem but what is about wannabe functions?
Gilad Bracha has written an interesting blog post about emulating functions in Dart. According to this article we are able to implement our fibonacci function as a wannabe function like that
and we can instantiate objects of this class being callable like “normal” functions.
These objects are no closures but behave like functions and they are transferable between isolates. Our solution would change into
which is very close to our intent.
The parallel package
Is it possible to build something like that in Dart? Yes. Take a look at the parallel package I propose. The parallel package
is in fact only a small wrapper around the worker package. It defines a parallel
map method and delegates all other method calls to
Iterable. So in fact it behaves almost like an iterable but provides the opportunity to launch a parallel map. In fact you can use it almost like a normal iterable.
Therefore the parallel package defines a function
parallel to transform any
Iterable collection into a
It furthermore defines a library private
MessagableFunction by extending the
Task concept of the Worker package (this library private class is in fact the bridge to the worker package).
PIterable class is implemented like this:
Now we have a function
parallel to transform each
into a parallelizable
PIterable form. And we have a
map method defined
PIterable which can be executed in parallel.
Due to the fact that
PIterable delegates all unknown method calls via
you can combine the parallel
map with all methods known from
Iterable (for example
Some closing remarks:
- Be aware: The parallel package has version 0.0.3 and main reason to release it is to foster discussions about pragmatic forms of parallelization in Dart (it is far from being complete or perfect)
- The parallel library is provided via http://pub.dartlang.org/
- The parallel library is also provided via Github
- This post is to foster discussions. So discussions, comments, remarks, opinions, etc. are very welcome.
Special thanks go to Diego Rocha and his awesome Worker library.
My last wish is about syntactic sugar
This here goes out to the Dart Language Specialists at Google. If there are thoughts how to improve the programmability of isolates you could think about some syntactic sugar.
It would be great if Dart had a syntax to create anonymous wannabe functions (not closures) so that
would be syntactic sugar for:
If Dart would provide that form of syntactic sugar it would be possible to come very close to a pragmatic form to express parallelization in Dart: