본문 바로가기
개발/자바스크립트

[자바스크립트] 최적화 #2 : 반복문 최적화(Duff's Device)

by 핸디(Handy) 2020. 7. 29.

이전 포스트에서 for문을 최적화하는 간단한 방법에 대해 알아보았습니다. 

2020/07/27 - [개발/자바스크립트] - [자바스크립트] 최적화 #1 : for 문을 최적화해보자

이번에는 for문을 최적화하는 2번째 방법에 대해 설명하겠습니다.

이전 포스트에서는 for문의 참조횟수를 줄임으로써 최적화를 진행했습니다.  이번에는 for문의 외부가 아닌 내부에서 최적화하는 기법을 소개하고자 합니다.

일반적으로 참조 최적화등을 아무리 많이 한다고 해봐야 반복문 안에 있는 코드가 오래걸린다면 아무 쓸모가 없습니다.

따라서 최적화의 1번째 원칙은 반복문 내부의 cost를 줄이는 것이고 제가 포스트 하는 것은 그 차후에 해야할 작업입니다.

아무튼

반복문을 실행했을때 반복문 내부의 코드를 실행하는 것 조차 시간이 걸립니다. 아무래도 내부에 있는 스코프를 설정하고 해제하고 하는 기본적인 작업에 시간이 걸리기 때문이죠.

따라서 10번 반복할 작업이 있다고 할 때, 이것을 5회로 2번 반복하면 어떨까요? 라는게 이번에 소개해드릴 기법의 시작입니다.

'Duff's Device'

이 기법은 반복문 몸체를 펼쳐 여러 번에 걸쳐서 했을 작업을 한 번에 하도록 하는 것입니다.

처음에는 C 언어로 구현되어 있었고 이를 자바스크립트에 처음 적용한 사람은 Jeff Greenberg 라고 합니다.

for ( var i = 0; i < items.length ; i++) {
	process(items[i]);
}

반복문이 있습니다. 간단한 코드죠.

이 코드를 다음과 같이 바꾸는 기법입니다.

var interations = Math.floor(items.length / 8 );
var startAt = items.length % 8 ;
var i = 0;

do {
	switch(startAt) {
    	case 0 : process(items[i++]);
        case 7 : process(items[i++]);
        case 6 : process(items[i++]);
        case 5 : process(items[i++]);
        case 4 : process(items[i++]);
        case 3 : process(items[i++]);
        case 2 : process(items[i++]);
    	case 1 : process(items[i++]);
    }
    startAt = 0;
} while (iterations--);

?? 뭔가 있어보이게 변했습니다. 

하지만 로직은 아주 간단합니다. 반복할 횟수를 8로 나눠서 한번에 여러번 실행하는 것입니다. 근데 잘 보시면 switch 문에 break 문이 없다는 걸 확인할 수 있습니다. 이게 테크닉의 중요한 부분입니다.

따라서 만약 items.length 가 20이라고 가정한다면, 원래의 for은 20번 반복해야하지만 개선된 반복문은 3번만 반복하면 됩니다. 

Duff's Device의 경우 반복횟수 1000회 미만이라면 성능에 큰 차이가 없다고 알려져있습니다. 하지만 1000회부터는 충분히 사용할 테크닉이라고 합니다. 

따라서 반복문인데 반복횟수가 너무 많다면 한번 시도해볼만한 테크닉입니다.

마지막으로 do-while로 개선된 반복문을 한번더 최적화한 코드로 글을 마무리하겠습니다.

switch문을 제거함으로써 최적화한 코드입니다.

var interations = items.length % 8;
var i = items.length - 1;

while (iterations){
	process(items[i--]);
    iterations--;
}

iterations = Math.floor(items.length / 8 );

while(iterations){
	process(items[i--]);
    process(items[i--]);
    process(items[i--]);
    process(items[i--]);
    process(items[i--]);
    process(items[i--]);
    process(items[i--]);
    process(items[i--]);
    iteration--;
}

 

댓글