LoginSignup
12
9

More than 3 years have passed since last update.

【JavaScript】指定した並列数で並列処理を行う関数

Last updated at Posted at 2019-05-21

記事「【備忘録】Javascriptで非同期処理を効率良くさばく方法」の「同時実行(concurrently)」で述べられていた
並列数を固定しての並列処理を
汎用関数に切り出してみた。

/**
 * 与えられたイテラブルから得られる関数を順に、
 * 指定された数まで並列に実行する。
 * 
 * @param iterable {Iterable<() => Promise<void>}
 *  実行したい関数を要素に持つイテラブル。
 *  各関数は引数を持たず、Promise を返す。
 * @param concurrency {number} この数まで並列に実行する。
 * @return {Promise<void>}
 *  全ての関数を実行し終えると resolve される Promise。
 */
async function runConcurrentlyAsync(iterable, concurrency) {
    const iterator = iterable[Symbol.iterator]();
    let index = 0; // ログ用
    const promises = Array.from({ length: concurrency }, (_, id) => {
        return new Promise(async (resolve) => {
            for (
                let result = iterator.next();
                !result.done;
                result = iterator.next()
            ) {
                const i = index++;
                console.log(`${id}: ${i}...`);

                await result.value();

                console.log(`        ...${id}: ${i}`);
            }

            resolve();
        });
    });
    await Promise.all(promises);
}

引数はイテラブルなので、配列やジェネレーターなどが使える。

ログには次のような情報が出力される。

0: 10...             // 0本目の並列処理が10番目の関数の処理を開始した。
            ...0: 10 // 0本目の並列処理が10番目の関数の処理を終了した。

使用例:

async function verySlowAsync(index) {
    return new Promise((resolve) => setTimeout(resolve, Math.random() * 1000));
}

function main() {
    const INIT = 0;
    const MAX = 100;
    const CONCURRENCY = 10; // 同時実行できる数を定義

    const generator = (function* createGenerator() {
        for (let index = INIT; index < MAX; index++) {
            yield async () => await verySlowAsync(index);
        }
    })();

    runConcurrentlyAsync(generator, CONCURRENCY);
}
main();

出力例:
0: 0...
1: 1...
2: 2...
3: 3...
4: 4...
5: 5...
6: 6...
7: 7...
8: 8...
9: 9...
        ...1: 1
1: 10...
        ...0: 0
0: 11...
        ...5: 5
5: 12...
        ...7: 7
7: 13...
        ...3: 3
3: 14...
        ...0: 11
0: 15...
        ...1: 10
1: 16...
        ...4: 4
4: 17...
        ...5: 12
5: 18...
        ...2: 2
2: 19...
        ...8: 8
8: 20...
        ...7: 13
7: 21...
        ...7: 21
7: 22...
        ...9: 9
9: 23...
        ...0: 15
0: 24...
        ...0: 24
0: 25...
        ...6: 6
6: 26...
        ...5: 18
5: 27...
        ...4: 17
4: 28...
        ...9: 23
9: 29...
        ...7: 22
7: 30...
        ...3: 14
3: 31...
        ...5: 27
5: 32...
        ...9: 29
9: 33...
        ...6: 26
6: 34...
        ...3: 31
3: 35...
        ...1: 16
1: 36...
        ...2: 19
2: 37...
        ...1: 36
1: 38...
        ...1: 38
1: 39...
        ...6: 34
6: 40...
        ...8: 20
8: 41...
        ...9: 33
9: 42...
        ...1: 39
1: 43...
        ...0: 25
0: 44...
        ...4: 28
4: 45...
        ...1: 43
1: 46...
        ...6: 40
6: 47...
        ...6: 47
6: 48...
        ...2: 37
2: 49...
        ...7: 30
7: 50...
        ...6: 48
6: 51...
        ...3: 35
3: 52...
        ...5: 32
5: 53...
        ...9: 42
9: 54...
        ...8: 41
8: 55...
        ...6: 51
6: 56...
        ...6: 56
6: 57...
        ...3: 52
3: 58...
        ...2: 49
2: 59...
        ...6: 57
6: 60...
        ...4: 45
4: 61...
        ...9: 54
9: 62...
        ...0: 44
0: 63...
        ...6: 60
6: 64...
        ...5: 53
5: 65...
        ...1: 46
1: 66...
        ...4: 61
4: 67...
        ...5: 65
5: 68...
        ...7: 50
7: 69...
        ...1: 66
1: 70...
        ...3: 58
3: 71...
        ...8: 55
8: 72...
        ...2: 59
2: 73...
        ...4: 67
4: 74...
        ...0: 63
0: 75...
        ...6: 64
6: 76...
        ...3: 71
3: 77...
        ...9: 62
9: 78...
        ...6: 76
6: 79...
        ...6: 79
6: 80...
        ...5: 68
5: 81...
        ...3: 77
3: 82...
        ...1: 70
1: 83...
        ...7: 69
7: 84...
        ...2: 73
2: 85...
        ...3: 82
3: 86...
        ...5: 81
5: 87...
        ...8: 72
8: 88...
        ...9: 78
9: 89...
        ...8: 88
8: 90...
        ...3: 86
3: 91...
        ...4: 74
4: 92...
        ...5: 87
5: 93...
        ...0: 75
0: 94...
        ...2: 85
2: 95...
        ...5: 93
5: 96...
        ...0: 94
0: 97...
        ...4: 92
4: 98...
        ...0: 97
0: 99...
        ...1: 83
        ...3: 91
        ...7: 84
        ...5: 96
        ...9: 89
        ...6: 80
        ...0: 99
        ...2: 95
        ...8: 90
        ...4: 98

12
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
9