_.chunk(array, [size=1])
하나의 배열을 지정한 개수만큼 여러 배열로 나누어 저장하는 함수입니다. 지정한 개수로 정확하게 나뉘지 않는다면 마지막 배열은 나뉜 나머지들로 채워지게 됩니다.
function chunk(array, size, guard) { if ((guard ? isIterateeCall(array, size, guard) : size === undefined)) { size = 1; } else { size = nativeMax(toInteger(size), 0); } var length = array ? array.length : 0; if (!length || size < 1) { return []; } var index = 0, resIndex = 0, result = Array(nativeCeil(length / size)); while (index < length) { result[resIndex++] = baseSlice(array, index, (index += size)); } return result; }
지정한 개수만큼 나누어 담기 위해 필요한 개수의 배열을 미리 선언해두고, slice를 이용해 직접 배열을 잘라서 담고 있습니다.
여러 방면에서 유용하게 사용 될 수 있겠지만, 생각해 볼 수 있는 예제 중 하나로는 처리해야 하는 큰 데이터 셋을 여러 작업자가 나누어 담당 할 때 작업량을 균등하게 나누어 주는 용도로 사용할 수 있겠습니다.
var async = require('async'); var fs = require('fs'); const array = new Array(1000).fill('./sample.txt'); function run(array, callback) { async.eachSeries(array, (filename, _callback) => { fs.createReadStream(filename) .on('data', function() {}) .on('end', function() { _callback(null); }); }, callback) } console.time('using _.chunk'); const slicedArrays = _.chunk(array, 100); async.each( slicedArrays, (slicedArray, callback) => run(slicedArray, callback), (err) => console.timeEnd('using _.chunk') ); console.time('not using _.chunk'); run(array, (err) => console.timeEnd('not using _.chunk'));
파일을 1,000번 읽는 작업을 두 가지 방법으로 시도하였습니다. 첫 번째는 _.chunk를 이용하여 100개씩 10개의 배열로 나누고 async.each 함수를 이용해 병렬로 처리하는 방법입니다. 두 번째는 간단하게 전체 배열 아이템을 순차적으로 읽는 방법입니다.
시도 할 때 마다 조금씩 달라지긴 하지만 대충 결과는 다음과 같습니다:
- using _.chunk: 288.824ms
- not using _.chunk: 556.763ms
_.chunk를 이용하여 I/O 작업을 병렬로 처리하는 것이 수행 시간을 약 두 배 정도 줄여주었습니다. OS를 괜히 놀리기 보다는 감당 할 수 있는 수준으로 일의 양을 조절하며 시키는 것이 성능 향상을 위해 좋겠죠.