코딩시 많이 하는 최적화 실수

카테고리 : 프로그래밍

이런걸 알고있으면 도움이 될것 같아 작성하게 되었습니다.

 

요즘에는 워낙 컴퓨팅 성능이 좋아져 구글같은 기업은 이런말을 하기도 했습니다.

제품 출시를 빠르게 하고 개발자가 쉽게 만드는게 컴퓨팅파워를 더 쓰더래도 좋다.

그러나 아래의 내용은 간단히 개발자의 실력으로 처리가능한 문제고,

하고 안하고의 차이가 많이 나기때문에 꼭 신경써서 처리하는것이 좋습니다.

 

 

많이 할 수 있는 코드 실수 예시

for, while 등 반복문에서 break를 안쓰는 경우

반복문에서 break를 쓰는것은 프로그램의 성능에 크게 도움이 됩니다.

겨우 1,000번 10,000번 반복하는거라면 크게 신경 쓸 필요가 없습니다.

(하지만, 자주 실행되는 코드라면? 반복문이 오래 실행된다면?)

 

그러나, 이런게 쌓여 컴퓨터에서는 수십만 수천만번 같은 작업을 반복하기도하고.

이미 결과가 나왔음에도 연산을 하고 있는건 낭비입니다.

 

이 때문에 break문으로(또는 언어에따라 Exit For) 반복을 중단하는 기능이 있는겁니다.

그런데, 정말 많은 경우에 이런걸 가르치지 않기도 하는데 매우 중요한 기능입니다.

 

이런 실수는 보통 입문자가 많이 할수있는 실수입니다.

 

 

String을 += 계속 덧붙이는 행동 (Javascript는 예외)

이거 문제가 많은 행동입니다.

만약에 JS로 아래와 같이 표현 했다고 할때.

var str='';
for(var i=0; i<5000000; i++){
	str += i+',';
}

위와 같은방식으로 코드를 작성하면 빠른 코드보다.. 2500000배 느리게 동작한다면?

 

위 코드는 아래 이미지와 같이 작동합니다.

  1. str 변수에 "0," 저장
  2. str 변수에서 "0," 읽고, "1,"를 추가하여 "0,1," 저장
  3. str 변수에서 "0,1,"읽고, "2,"를 추가하여 "0,1,2," 저장

위의 예시를 볼때 뭐가 문제인지 인지하지 못할수도 있습니다. 이건 아마 초급~중급자에서 많이 할수있는 실수가 아닐까 합니다.

 

위의 연산에서는 CPU가 항상 관여하고 있고 불필요하게 계속 읽는 작업을 합니다.

 

제일 빠른 작업은 아래와 같은것이다. (쉽게말하면 3턴만에 끝나는 작업)

0, 1, 2,

 

그냥 넣고 나중에 합하는 과정을 한다면 가장 적은 회수로 실행되겠지만

위의 +=으로 문자를 합하는 행동은 (쉽게말하면 6턴만에 끝나는 작업)

0,    
0, 1,  
0, 1, 2,

3번 반복을했는데 2배 느려졌습니다. (빨간부분은 읽고 다시 쓰고하는 작업이 추가됩니다.)

 

이럴때는 메모리를 이용한 작업을 해야됩니다.

var str=[];
for(var i=0; i<5000000; i++){
	str.push(i);
}
console.log(str.join(","))

위의 코드와는 조금 다릅니다.

결과는 "… 4999998,4999999," 으로 끝나는 첫번째 코드와는 달리

join함수는 마지막 ","가 없기 때문에 "4999998,4999999" 이 될것이다.

(join함수는 사이에 정해진 문자를 넣을수 있습니다.)

 

물론, 아래와 같이 빈 문자열을 넣으면 "… 4999998,4999999," 마지막에 "," 로 끝낼수 있습니다.

var str=[];
for(var i=0; i<5000000; i++){
	str.push(i);
}
str.push("");
console.log(str.join(","))

 

배열을 사용해서 메모리에 각각 넣었고, join 함수를 사용하면 메모리에서 하나씩 읽어 결합하여 출력한다.

 

C#, JAVA, JS, PYTHON 같은 고급언어들은 내부 처리기 방식에 따라 처리가 조금씩 다를수 있으나.

이런걸 수정하면 며칠씩 걸리는 코드를 몇 초 이내로 줄일수도 있습니다.

(≒ 몇초 이내에 실행될 코드를 "+="을 잘못사용하면 며칠씩 걸리게 만들수도 있습니다.)

 

STRING 에서 +=같은 작업은 비효율적이라 C#, JAVA등에서는 빠른 처리를 위해 따로 StringBuilder 같은 옵션도 있다는점.

(그러나 간단하고 짧은 내용을 합한다면 그냥 쓰셔도 무방합니다.)

 

C#, JAVA등에서는 StringBuilder를 이용해서 메모리를 이용하여 문자처리를 해보시는것을 추천드립니다.

 

예외

Javascript는 이 방법이 더 빠릅니다.

 

 

 

For문에서 함수를 계속 실행시키는 코드

2021-09-22 추가

최근 그누보드(CMS) 코드를 보고 경악했다.

오래된 CMS임에도 불구하고, 성능이 최적화되지 않은 코드가 많이 있기 때문이었다.

// common.php 중.. 601번째 줄
// https://github.com/gnuboard/gnuboard5/blob/fdbbe2d307e02dc1f720c427be751c42d53306fd/common.php#L601
for ($i=0; $i<count($pattern); $i++) {
    $pattern[$i] = trim($pattern[$i]);
    if (empty($pattern[$i]))
        continue;

    $pattern[$i] = str_replace(".", "\.", $pattern[$i]);
    $pattern[$i] = str_replace("+", "[0-9\.]+", $pattern[$i]);
    $pat = "/^{$pattern[$i]}$/";
    $is_possible_ip = preg_match($pat, $_SERVER['REMOTE_ADDR']);
    if ($is_possible_ip)
        break;
}

for문은 for(1번 영역; 2번 영역; 3번 영역) 으로 나뉜다.

동작순서는 아래와 같다.

  1. 1번 영역의 변수를 선언한다. (for문 내에서의 지역변수)
  2. 2번 영역의 참 여부를 구해서 참이라면 for문 내부 코드를 실행한다.
    1. for문 내부의 코드를 실행한다.
    2. 3번 영역의 코드를 실행한다.
  3. 2번 영역의 참 여부를 구해서 참이라면 for문 내부 코드를 실행한다.
    1. for문 내부의 코드를 실행한다.
    2. 3번 영역의 코드를 실행한다.
  4. 2번 영역의 참 여부를 ...

그렇습니다. for문 내부의 두번째 영역은 for문 실행마다 항상 선행되는 코드로

이 곳에 count함수를 사용하는 경우 불필요하게 매번 array의 크기를 계산하는 작업을 추가로 수행합니다.

 

// common.php 중.. 601번째 줄
// https://github.com/gnuboard/gnuboard5/blob/fdbbe2d307e02dc1f720c427be751c42d53306fd/common.php#L601
$count=count($pattern);
for ($i=0; $i<$count; $i++) {
    $pattern[$i] = trim($pattern[$i]);
    if (empty($pattern[$i]))
        continue;

    $pattern[$i] = str_replace(".", "\.", $pattern[$i]);
    $pattern[$i] = str_replace("+", "[0-9\.]+", $pattern[$i]);
    $pat = "/^{$pattern[$i]}$/";
    $is_possible_ip = preg_match($pat, $_SERVER['REMOTE_ADDR']);
    if ($is_possible_ip)
        break;
}

물론 count 함수는 실행속도가 오래걸리진 않습니다.

그러나 이런 작업들이 반복적으로 쌓인다면, 실행이 느려지게됩니다.

 

https://www.php.net/manual/en/function.count.php#114924

'프로그래밍' 카테고리의 다른 글

확률(랜덤값) 알고리즘은 어떻게 작동할까?  (5) 2019.04.25

 

저작권 보호안내
무단 전재, 재배포 행위는 금지됩니다. (글을 복사하여 게시금지)
본문의 일부(링크용 문장) 인용은 가능하지만, 출처와 링크(a 태그)를 남기셔야 됩니다.
(웹툴을 이용하고, 스크린샷/녹화하는것은 상관없습니다.)

예외적으로. 저에게 허락받은 경우에는 본문을 전재할 수 있습니다.

만약, 본문 공유를 원하신다면 링크 공유를 해주세요

저작권 정책 확인하기
링크 공유하기

 댓글