kubo39's blog

ただの雑記です。

std.parallelismざっくり

D言語で並列処理を扱うためのライブラリとして、標準ライブラリにstd.parallelismがある。

これはstd.algorithmやstd.rangeを使うのとほとんど同じような感じで処理が書ける。

以下の処理はOSスレッドによって並列に実行される。 デフォルトのワーカースレッド(内部ではtaskPoolという言葉を使っている)のスレッド数はCPUコア数-1個である。

    // 標準ライブラリの例から持ってきたもの
    import std.algorithm.iteration : map;
    import std.math : approxEqual;
    import std.parallelism : taskPool;
    import std.range : iota;

    enum n = 1_000_000;
    enum delta = 1.0 / n;

    alias getTerm = (int i)
    {
        immutable x = ( i - 0.5 ) * delta;
        return delta / ( 1.0 + x * x ) ;
    };

    immutable pi = 4.0 * taskPool.reduce!"a + b"(n.iota.map!getTerm);

    assert(pi.approxEqual(3.1415926));

タスク

ワーカースレッドが実行する処理の単位をタスクと呼ぶ。 スレッドはタスクキューの先頭から順にタスクを取っていき、タスクの実行が終わったら次のタスクをまたタスクキューから取り出していく。 タスクは少ない場合はスタックに,多い場合はヒープに連続した領域として確保する。(どうもallocaがバグで使えないという理由でmallocを使っているようだ) タスクは随時追加したり、専用の実行スレッドを新たに割り当てて実行させたりすることができる。

実は提供しているparallelやmap、reduceの内部では先頭のタスクはメインスレッドが実行するようになっており、さらに以降のタスクでワーカースレッドがタスクをとらなかった場合にそなえてメインスレッド側で肩代わり実行するようなメカニズムになっている。