On Wednesday, 18 October 2017 at 11:34:57 UTC, Nordlöw wrote:
Another thing...how should the synchronization between the
fibers figure out when the total number of fibers have reached
one million?...via an atomic counter fed by reference to the
constructor...or are there better ways? Because I do need an
atomic reference counter here, right?
This is how I did it:
import core.thread : Fiber;
class MyFiber : Fiber {
int _depth;
ulong _index;
ulong _value;
this(int depth, ulong index) {
super(&run);
_depth = depth;
_index = index;
}
void run() {
if (_depth == 6) { // 10^6 == 1 million, so stop here.
_value = _index;
return;
}
_value = 0;
foreach (i; 0..10) { // Line 23
auto e = new MyFiber(_depth+1, _index * 10 + i);
e.call();
_value += e._value;
}
}
}
unittest {
import std.stdio : writeln;
import std.datetime.stopwatch : StopWatch, AutoStart;
auto sw = StopWatch(AutoStart.yes);
auto a = new MyFiber(0, 0);
a.call();
sw.stop();
assert(a._value == 499999500000);
writeln(a._value, " after ", sw.peek);
}
And how do I parallelize this over multiple worker threads?
AFAICT fibers are by default all spawned in the same main
thread, right?
True. Well, they're not really spawned on any thread - they're
allocated on the heap, have their own stack, and are run on
whichever thread happens to invoke their call() method.
I experimented a little bit with parallelism, and the easiest
definitely is to replace line 23 with this:
foreach (i; taskPool.parallel(10.iota, 1)) {
It seems to make very little difference in terms of run time,
though. I tried using a mix of these approaches - parallel at low
depth, basically just to fill up the cores, and serial closer to
the leaves. The difference is still negligible, so I assume the
losses are elsewhere.
--
Biotronic