6

I know that Rust can run loops with lightweight threads. Something like:

use task::spawn;

fn main() {
  for 100.times {
    do spawn {
      io::println("Hello");
    }
  }

How I can do this in D?

wegry
  • 7,046
  • 6
  • 39
  • 59
Suliman
  • 1,469
  • 3
  • 13
  • 19

2 Answers2

11

Relevant API doc: std.parallelism

Here are a few of ways of accomplishing your example:

Parallel foreach, using a TaskPool's parallel:

foreach (i, val; taskPool.parallel(new int[50])) {
    writeln("Hello:", i);
}

Regular foreach, adding tasks to a task pool using put:

foreach (i; 0 .. 50) {
    auto t = task!writeln("Hello:", i);
    taskPool.put(t);
}

Execute each task in a new thread instead of a TaskPool:

foreach (i; 0 .. 50) {
    auto t = task!writeln("Hello:", i);
    t.executeInNewThread();
}

Rust's runtime has a built-in task scheduler, but with D, this is implemented as a library. That being said, the second is the closest in terms of functionality, and the last is the closest in terms of syntax (but they're OS threads, not lightweight).

In D, lightweight threads are explicitly controlled by the programmer. A TaskPool is analogous to the scheduler in Rust/Go, but it gives more fine-grained control to the programmer. This makes it slightly more verbose, but it also gives you parallel versions of map, reduce, foreach, etc. This makes it easier to represent more complex algorithms efficiently.

Running each example should give you the expected result: out of order writes.

Note:

From the doc:

The worker threads in this pool are daemon threads, meaning that it is not necessary to call TaskPool.stop or TaskPool.finish before terminating the main thread.

The second example doesn't wait until all workers are done, so in testing you may get no results (when main finishes, all remaining tasks are killed). You may need to block by calling finish:

taskPool.finish(true);
beatgammit
  • 19,817
  • 19
  • 86
  • 129
  • Can I do something like: for (int i=0; i<10; i.parallel) { writeln("processing ", i); } ? – Suliman Mar 09 '13 at 11:41
  • @Suliman - Is you question about syntax? Because that's nearly exactly what the first two do (the second more so). You have to use the taskPool object though because D won't do it for you. – beatgammit Mar 09 '13 at 11:47
  • In that case no. D does not schedule light-weight threads for you, so you have to use a library. The second example is the closest. – beatgammit Mar 09 '13 at 21:54
8

D has no built-in abstractions for lightweight threads. Instead, you can:

  • use threads (see std.concurrency and std.parallelism)
  • use fibers, and multitask manually by explicitly yielding execution
  • use a library such as Vibe.d, which implements asynchronous I/O using fibers and implicit yielding on blocking operations
Vladimir Panteleev
  • 24,651
  • 6
  • 70
  • 114