이런걸 알고있으면 도움이 될것 같아 작성하게 되었습니다.
요즘에는 워낙 컴퓨팅 성능이 좋아져 구글같은 기업은 이런말을 하기도 했습니다.
제품 출시를 빠르게 하고 개발자가 쉽게 만드는게 컴퓨팅파워를 더 쓰더래도 좋다.
그러나 아래의 내용은 간단히 개발자의 실력으로 처리가능한 문제고,
하고 안하고의 차이가 많이 나기때문에 꼭 신경써서 처리하는것이 좋습니다.
많이 할 수 있는 코드 실수 예시
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배 느리게 동작한다면?
위 코드는 아래 이미지와 같이 작동합니다.
- str 변수에 "0," 저장
- str 변수에서 "0," 읽고, "1,"를 추가하여 "0,1," 저장
- 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번 영역의 변수를 선언한다. (for문 내에서의 지역변수)
- 2번 영역의 참 여부를 구해서 참이라면 for문 내부 코드를 실행한다.
- for문 내부의 코드를 실행한다.
- 3번 영역의 코드를 실행한다.
- 2번 영역의 참 여부를 구해서 참이라면 for문 내부 코드를 실행한다.
- for문 내부의 코드를 실행한다.
- 3번 영역의 코드를 실행한다.
- 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 함수는 실행속도가 오래걸리진 않습니다.
그러나 이런 작업들이 반복적으로 쌓인다면, 실행이 느려지게됩니다.
'프로그래밍' 카테고리의 다른 글
확률(랜덤값) 알고리즘은 어떻게 작동할까? (5) | 2019.04.25 |
---|
저작권 보호안내
무단 전재, 재배포 행위는 금지됩니다. (글을 복사하여 게시금지)
본문의 일부(링크용 문장) 인용은 가능하지만, 출처와 링크(a 태그)를 남기셔야 됩니다.
(웹툴을 이용하고, 스크린샷/녹화하는것은 상관없습니다.)
예외적으로. 저에게 허락받은 경우에는 본문을 전재할 수 있습니다.
만약, 본문 공유를 원하신다면 링크 공유를 해주세요
저작권 정책 확인하기링크 공유하기