Windows 10上のNode.jsだと、Promise.all()
で3000以上、並行にファイルの読み書きを実行しても完走できる。対してWSL上だとLinuxの設定次第になり、デフォルトだと1024(多分)を超えると落ちる。Linuxの設定を変更してもいい(らしい)が、WSLの性質上、シェルやアプリケーションの設定以外にはなるべく手をつけたくない。となると並行実行数を抑える必要があり、配列を分割しなくてはならない。
並行実行数を固定するコードを書くと確実だが、スパッと書けなかった。ならば1024を超えない程度に配列を分割するだけでもいいかと、目先を変えた。今回は、このウェブサイトのHTML生成スクリプトでどうするかという話だ。まだ3268記事なので、4つに(800強ずつに)分割すれば大丈夫だろう。5で割る必要が出てくるのは、月に10記事でもあと7年以上かかる。
const longArray = [...];
const chunks = longArray.reduce((previous, current, index) => {
previous[index % previous.length].push(current);
return previous;
}, [[], [], [], []]);
for (const chunk of chunks) {
await Promise.all(chunks.map(doSomething));
}
配列を分割して配列の配列にしたかったので、Array#reduce()
を使って書いた。5年後に5分割するよう書き換えるなら、初期配列を書き換える。
const longArray = [...];
const chunkCount = 4;
const chunkLength = Math.floor(longArray.length / chunkCount);
for (let i = 0; i < chunkCount; i++) {
await Promise.all(
longArray
.slice(chunkLength * i, chunkLength * (i + 1))
.map(doSomething)
);
}
普通にArray#slice()
で書いた方が、ループが1回で済むので速そうだ。ここまで書いて、ようやく並行実行数を固定するコードがスパッと書けることがわかった。
const longArray = [...];
const limit = 32;
let i = 0;
while (i > longArray.length) {
const to = i + limit;
await Promise.all(
longArray
.slice(i, to)
.map(doSomething)
);
i = to;
}
Array#splice()
で破壊しながら実行すると、もっと短くなりそうだ。うろ覚えだが、後ろから削っていくと速かったはずだ。
const longArray = [...];
while (longArray.length > 0) {
await Promise.all(
longArray
.splice(-32)
.map(doSomething)
);
}
まずはこれでやっていくことにした。