Waitgroups in D Programming Language

Our first example demonstrates the use of a TaskGroup, which is similar to a wait group. It allows us to wait for multiple tasks to finish.

import std.stdio;
import std.concurrency;
import core.thread;
import core.time;

// This is the function we'll run in every task.
void worker(int id)
{
    writefln("Worker %d starting", id);

    // Sleep to simulate an expensive task.
    Thread.sleep(dur!"seconds"(1));
    writefln("Worker %d done", id);
}

void main()
{
    // This TaskGroup is used to wait for all the
    // tasks launched here to finish.
    auto tg = new TaskGroup;

    // Launch several tasks and add them to the TaskGroup.
    foreach (i; 1 .. 6)
    {
        // Wrap the worker call in a task that makes sure to tell
        // the TaskGroup that this worker is done. This way the worker
        // itself does not have to be aware of the concurrency primitives
        // involved in its execution.
        tg.create({
            worker(i);
        });
    }

    // Block until all tasks in the TaskGroup are done.
    tg.wait();

    // Note that this approach has no straightforward way
    // to propagate errors from workers. For more
    // advanced use cases, consider using other concurrency
    // primitives provided by D.
}

To run the program, save it as taskgroups.d and use the D compiler:

$ dmd taskgroups.d
$ ./taskgroups
Worker 3 starting
Worker 1 starting
Worker 2 starting
Worker 5 starting
Worker 4 starting
Worker 3 done
Worker 1 done
Worker 2 done
Worker 5 done
Worker 4 done

The order of workers starting up and finishing is likely to be different for each invocation.

In this D version, we use a TaskGroup instead of a WaitGroup. The TaskGroup in D serves a similar purpose, allowing us to create and manage multiple concurrent tasks. We create tasks using tg.create() instead of launching goroutines, and we use tg.wait() to wait for all tasks to complete, similar to wg.Wait() in Go.

The worker function remains largely the same, but we use D’s writefln for formatted output and Thread.sleep for simulating work.

Note that D’s concurrency model is different from Go’s, but this example demonstrates a similar concept of managing multiple concurrent tasks and waiting for their completion.