Inside Lodash: _.chunk

 

_.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를 괜히 놀리기 보다는 감당 할 수 있는 수준으로 일의 양을 조절하며 시키는 것이 성능 향상을 위해 좋겠죠.

 

Lodash 4.16.1

 

 

 

Leave a comment