新しいことにはウェルカム

技術 | 電子工作 | ガジェット | ゲーム のメモ書き

JavaScriptで同時実行数を指定しつつ並行実行させる方法

沢山のタスクがあって並行処理したいのですが、全てを並行実行させると重くなってしまうので、同時実行数を指定しつつ並行実行させたい時があります。

恥ずかしながらJavaScriptでそれをやる方法を知らず、代案として、処理したいタスクを同時実行数づつに分けて、一まとまりをPromise.all()で実行していました。

しかしこれだと、一まとまりのPromise.all()に入れたタスクが全て終了してから、次の一まとまりの処理を行うので、常に一定数の同時実行ではないのでモヤモヤしていたのですが、JavaScritで同時実行数を指定しつつ並行実行させる記事を見つけました。

qiita.com

qiita.com

なるほど~。同時実行数だけPromiseを起動して、そのPromiseの中でタスクを実行すればいいんですね。

いや~、勉強になりました!

ずっとモヤモヤしていたのが解決してスッキリしました!ありがとうございます。

写経

実際に手を動かさないと身につかないので、記事を参考にリライトしてみました。

function task(workerId: number, dataId: number, input: number) {

    return new Promise((resolve, reject) => {
        console.log(`TASK START : workerId->${workerId} dataId->${dataId} input->${input}`);
        setTimeout(() => {
            console.log(`----- TASK END : workerId->${workerId} dataId->${dataId} input->${input}`);
            resolve({
                workerId,
                dataId,
                input,
                result: input * 10,
            });
        }, input * 1000);
    });
}

(async () => {

    // promise間で共有するデータ
    const data = [4, 3, 2, 1, 0, 3, 2, 1]; // 処理するデータ
    let dataIdx = 0; // 処理位置

    const workerNum = 3; // 同時実行数
    const workers = [];
    for (let workerIdx = 0; workerIdx < workerNum; workerIdx++) {

        const p = new Promise(async (resolve, reject) => {

            const results: any = [];
            while (dataIdx < data.length) {
                const idx = dataIdx;
                dataIdx++;  // awaitの前にインクリメントする
                const res = await task(workerIdx, idx, data[idx]);
                results.push(res);
            }

            resolve(results);

        });

        workers.push(p);
    }

    // 終了待ち
    const res = await Promise.all(workers);

    // 結果取得
    for (const p of res) {
        for (const v of (p as any)) {
            console.log(v);
        }
    }
})();

ポイントとしては、同時実行数だけPromiseを作成して、そのPromise間で入力データを共有させるところでしょうか。

注意点としては、タスクは非同期実行されるので、タスク関数を呼び出す前に、処理位置を進めておくのを忘れずに。

感想など

今回の例は、入力データ数が決まっている場合のみ有効で、ストリームなど、データ数が未定の場合には使えません。何とかできないかと色々試してみましたが挫折しました…。

関連カテゴリー(JavaScript)記事

www.kwbtblog.com

www.kwbtblog.com

www.kwbtblog.com

www.kwbtblog.com

www.kwbtblog.com

www.kwbtblog.com

www.kwbtblog.com

www.kwbtblog.com

www.kwbtblog.com

www.kwbtblog.com

www.kwbtblog.com

www.kwbtblog.com

www.kwbtblog.com

www.kwbtblog.com