최적화가 시기상조입니까?


82

Knuth가 말했듯이,

약 97 %의 시간 동안 작은 효율성은 잊어야합니다. 조기 최적화는 모든 악의 근원입니다.

이것은 "가장 효율적인 루프 메커니즘", "SQL 최적화 기술"과 같은 질문에 대한 Stack Overflow 답변에서 자주 나오는 것입니다. ( 등등 ). 이러한 최적화 팁 질문에 대한 표준 답변은 코드를 프로파일 링하고 먼저 문제가 있는지 확인하고 그렇지 않은 경우 새로운 기술이 필요하지 않은지 확인하는 것입니다.

내 질문은 특정 기술이 다르지만 특별히 모호하거나 난독 화되지 않은 경우 실제로 조기 최적화로 간주 될 수 있습니까?

다음은 Randall Hyde의 The Fallacy of Premature Optimization 이라는 관련 기사 입니다.


41
그것은 일종의 아이러니 그 자체가 너무 빨리 견적을 최적화 한 "조기 최적화는 모든 악의 뿌리입니다"소리 많은 사람들 : (계속)
일부

21
"우리는 시간의 97 %에 대해 말할 작은 효율성에 대해 잊지한다 : 조기 최적화는 모든 악의 뿌리입니다 그러나 우리는 그 중요한 3 %에 우리의 기회를 통과해서는 안된다."(도널드 크 누스를)
일부

2
나는 이것을 말한 것이 CA Hoare라고 믿습니다. Knuth도 그렇게 말합니다.
jamesh

1
그래, 내가 믿는 나머지를 추가 그를 의역, 토니 호어 먼저 "조기 최적화는 모든 악의 부분의 루트입니다"라고하지만, 크 누스 / 인용
nickf

2
나는 인용문이 가장 자주 남용되고 문맥에서 벗어난 것에 동의하지만, 정의상 "조기"때문에 항상 옳다 (그러나 이것은 엉성한 디자인과 코드에 대한 정당화로 가장 자주 잘못 사용됨). 정의에 따라 최적화가 개발 중 가장 적절한 시점에서 발생했다면, 설계 중이 든 다른 시점이든 그것은 "조기"가 아닙니다.
Lawrence Dol 2011 년

답변:


103

Don Knuth 는 컴퓨터 코드의 가장 중요한 기능이 프로그래머의 의도를 인간 독자에게 전달하는 것이라고 믿었 기 때문에 문학적 프로그래밍 운동을 시작했습니다 . 성능이라는 이름으로 코드를 이해하기 어렵게 만드는 코딩 관행은 조기 최적화입니다.

최적화라는 이름으로 도입 된 특정 관용구는 너무 인기가 많아서 모든 사람이이를 이해하고 너무 이른시기 가 아니라 예상 됩니다. 예는 다음과 같습니다.

  • 사용 포인터 연산 대신 배열 표기 이러한 관용구의 사용 등을 포함하여, C의

    for (p = q; p < lim; p++)
    
  • 다음과 같이 전역 변수를 Lua의 지역 변수 에 다시 바인딩

    local table, io, string, math
        = table, io, string, math
    

이러한 관용구를 넘어 위험에 처한 지름길을 선택하십시오 .

모든 최적화는

  • 프로그램이 너무 느립니다 (많은 사람들이이 부분을 잊어 버립니다).

  • 당신은이 측정 (프로필 또는 유사한) 것을 보여주는 최적화 물건을 향상시킬 수를 .

(메모리 최적화도 허용됩니다.)

질문에 대한 직접적인 답변 :

  • 만약 당신의 "다른"기술 이 프로그램을 이해하기 어렵게 만든 다면 , 그것은 조기 최적화 입니다.

편집 : 의견에 대한 응답으로 삽입 정렬과 같은 간단한 알고리즘 대신 퀵 정렬을 사용 하는 것은 모든 사람이 이해하고 기대하는 관용구 의 또 다른 예입니다 . (라이브러리 정렬 루틴을 사용하는 대신 자신 만의 정렬 루틴을 작성한다면, 아주 좋은 이유가 있기를 바랍니다.)


13
귀하의 정의에 따라; 빠른 정렬 구현이 거품 정렬보다 읽고 이해하기 어려운 경우 조기 최적화입니다. 메모리를 최적화 할 수 없습니까? 큰 희소 행렬에 대해 동일한 예를 찾아보십시오. IMHO, 대부분의 최적화는 설계 단계에서 발생해야합니다. 즉, 아주 일찍.
SmacL

1
@frankodwyer :하지만 포인터를 늘리는 것이 카운터를 늘리고 배열 표기법을 사용하는 것보다 빠를 수 있으며 조기 최적화가 될 수 있습니다.
Joachim Sauer

5
@Norman : 퀵소트가 지금은 어디에나 있지만 처음 발명되었을 때가 아니 었기 때문에 QED는 작성자가 업무를 망칠 수없는 조기 최적화였습니다.
Lawrence Dol

5
@Software Monkey : 물론입니다. 모든 CS 연구는 납세자의 돈 낭비이므로 즉시 중단해야합니다.
Norman Ramsey

11
발명 한 것을 포함한 모든 정렬 알고리즘은 적절한 주석과 함께 sortQuickly (...)라는 별도의 함수로 작성하면 명확하고 간결합니다.
일리아 n.

40

IMHO, 최적화의 90 %는 인식 된 현재 및 더 중요한 미래 요구 사항을 기반으로 설계 단계에서 발생해야합니다. 애플리케이션이 필요한 부하로 확장되지 않아 프로파일 러를 제거해야하는 경우 너무 늦게 남겨두고 IMO는 문제를 해결하지 못하는 동안 많은 시간과 노력을 낭비하게됩니다.

일반적으로 유일하게 가치있는 최적화는 속도 측면에서 수십 배의 성능 향상을 얻거나 스토리지 또는 대역폭 측면에서 승수를 얻는 최적화입니다. 이러한 유형의 최적화는 일반적으로 알고리즘 선택 및 저장 전략과 관련이 있으며 기존 코드로 되 돌리는 것이 매우 어렵습니다. 시스템을 구현하는 언어에 대한 결정에 영향을 미칠 수 있습니다.

따라서 제 조언은 코드가 아닌 요구 사항에 따라 초기에 최적화하고 앱의 가능한 연장 수명을 고려하십시오.


6
나는 당신의 "너무 늦게 떠났다"는 결론에 동의하지 않습니다. 기본적으로 프로파일 링은 가정이 유지되지 않을 때 필요하며 프로파일 러는 어떤 가정이 깨 졌는지 알려주기 위해 필요합니다. 예를 들어 Java의 StringBuffers에 대한 "위치 0에서 문자 삭제"는 junit 테스트에서는 잘 작동하지만 큰 문자열에서는 매우 느립니다. 프로파일 러가 그것을 범인으로 지적하기 전까지는 그 코드를 의심하지 않았습니다!
Thorbjørn Ravn Andersen

7
내 경험을 바탕으로 "프로파일 러가 필요하면 이미 늦었습니다"에 동의합니다. 대부분의 성능 문제는 단일 병목 현상이 아니라 여러 기여자에게 퍼져 있습니다. 그러나 나는 낮은 수준의 코드와 비용에 대한 강한 배경을 가지고 있으며, 첫 번째 문자열 문자의 제거에 의존하는 (상당히 반복되는) 모든 것을 본능적으로 피했을 것입니다. "설계 중 최적화"에 +1.
peterchen

@peterchen은 호기심에서 "첫 번째 문자열 문자 제거"를 위해 무엇을했을까요?
Ghos3t

1
@ user258365 : 무차별 대입은 하위 문자열에 대한 복사본을 만들 필요가없는 문자열 표현을 사용하는 것입니다. 불변의 참조 카운트 문자열에 대해서는 "거의 사소한"것입니다. 또는 대체 (의사 코드)와 같은 알고리즘 변경 while (s[0]==' ') s = s.substring(1) for(i=0; i<s.len && s[i]==' '; ++i); s=s.substring(i)--- 그러나 잠재적 인 성능 문제를 이미 알고 있어야합니다 (프로파일 러는 여기서 지속적인 학습을위한 유용한 도구입니다).
peterchen

@ ThorbjørnRavnAndersen, 팀의 프로젝트 완료를 돕기 위해 컨설턴트로 일했지만 심각한 성능 문제가 계획되지 않았기 때문에 불가능했습니다 (스파게티 코드 외에). 모든 환자의 이력이있는 연대순 차트를 보여 주기로되어있었습니다. 전 세계를 가져 오는 Google지도처럼 전체 데이터에 대해 단일 요청이 이루어졌습니다. 나중에 프로파일 링을 예상하고 잘못된 코드를 개발하면 프로젝트가 실패했습니다.
Pedro Amaral Couto

30

프로파일 링하지 않았다면 시기상조입니다.


3
나는 그이면에있는 아이디어에 동의하지만 또한 구현이 CPU주기에 완전히 구속되지 않는 한 재현 가능하고 일반화 될 수있는 측정을 얻는 것이 어렵고 더 안정적 일수록 덜 현실적입니다.
peterchen

1
위의 대답에 대한 문제는 코딩하기 전에 알고리즘을 최적화 할 수 없다는 것을 의미합니다. 내 작업 방식은 기능 요구 사항을 충족하도록 알고리즘을 설계하는 경향이 있습니다. 성능 요구 사항 (예 : 복잡도가 높고 큰 데이터 세트에 도달 할 가능성이 높음)에 실패 할 가능성이 있는지 확인하고 코딩을 시작하기 전에 알고리즘을 최적화하십시오. 최적화는 최적의 솔루션에 도달하기위한 단순한 개선이며, 종종 설계 단계에서 가장 효율적으로 수행됩니다.
SmacL

2
동의하지 않습니다. Knuth는 작은 효율성에 대해 이야기하고있었습니다. 최적화는 종종 설계 단계에서 발생합니다. 적절한 데이터 구조와 알고리즘을 선택해야하며, 이는 종종 성능에 큰 영향을 미치며 나중에 교환 할 수 없습니다.
haslersn

@haslersn : "Knuth는 작은 효율성에 대해 이야기하고있었습니다."Donald Knuth : "오늘날 많은 소프트웨어 엔지니어들이 공유하는 일반적인 통념은 소규모의 효율성을 무시하도록 요구합니다. 그러나 이것은 단순히 남용에 대한 과잉 반응이라고 생각합니다. 확립 된 엔지니어링 분야의 12 % 개선은 쉽게 얻을 수 있지만 한계로 간주되지 않습니다. (...) "
Pedro Amaral Couto

27

내 질문은 특정 기술이 다르지만 특별히 모호하거나 난독 화되지 않은 경우 실제로 조기 최적화로 간주 될 수 있습니까?

음 .. 비용면에서 동일한 두 가지 기술 (사용, 읽기, 수정에 대한 동일한 노력)이 준비되어 있고 하나가 더 효율적입니다. 아니요, 더 효율적인 것을 사용하는 것은이 경우에는 시기상조가 아닙니다.

코드 작성을 중단하여 일반적인 프로그래밍 구조 / 라이브러리 루틴에 대한 대안을 찾다가, 작성중인 내용의 상대적인 속도를 알고있는 경우에도 어딘가에 더 효율적인 버전이있을 가능성이 실제로는 중요하지 않습니다. .. 그건 조기.


3
동의합니다. 하나의 알고리즘이 사용 사례에 더 효율적이라는 것을 알고 있다면 반드시 더 효율적인 알고리즘을 사용하십시오. 가장 효율적인 알고리즘을 모른다면 가지고있는 알고리즘을 사용하고 나중에 프로필을 작성하여 문제인지 확인하십시오.
grepsedawk

10

다음은 조기 최적화를 피하는 전체 개념에서 볼 수있는 문제입니다.

말하는 것과하는 것 사이에는 단절이 있습니다.

저는 많은 성능 튜닝을 수행하여 잘 설계된 코드에서 큰 요소를 짜내 어 조기 최적화없이 수행 된 것처럼 보입니다. 여기에 예가 있습니다.

거의 모든 경우에 최적이 아닌 성능의 이유는 내가 galloping generality 라고 부르는 이유 인데, 이는 추상적 인 다중 계층 클래스와 철저한 객체 지향 설계를 사용하기 때문입니다. 단순한 개념은 덜 우아 하지만 완전히 충분합니다.

알림 기반 아키텍처, 단순히 객체의 부울 속성을 설정하는 것만으로도 활동의 무한한 파급 효과를 가질 수있는 정보 숨김과 같은 이러한 추상적 인 디자인 개념을 가르치는 교재에서 그 이유는 무엇입니까? 효율성 .

그래서, 그것이 조기 최적화였습니까?


추상화 및 일반화의 주요 문제 중 하나를 설명하므로이 답변이 마음에 듭니다. 더 광범위한 사용 사례를 지원하기 위해 클래스 계층을 일반화하면 가장 일반적인 사용 사례의 성능을 심각하게 손상시키기가 너무 쉽습니다. 또한 의도 된 사용 규모에 대해 허용 가능한 수준의 성능으로 기능이 제공되는지 여부를 확인하지 않고 특정 기능을 제공하는 클래스에 쉽게 연결됩니다.
SmacL 2010

1
"단순한 개념이 덜 우아 하지만 완전히 충분한 곳"단순한 코드가 요구 사항을 충족 할 때 복잡한 코드는 단순한 코드보다 우아하지 않습니다. (하지만 누군가가 더 복잡한 경우에 실행하려고하면 지원되지 않는 상태 / 입력에 대한 명확한 표시와 함께 간단한 코드가 실제로 폭발하도록해야한다고 주장합니다.)
jpmc26

8

먼저 코드가 작동하도록합니다. 둘째, 코드가 올바른지 확인하십시오. 셋째, 빨리하십시오.

3 단계 이전에 수행 된 코드 변경 은 확실히 시기상조입니다. 이전에 만든 디자인 선택 (예 : 적합한 데이터 구조 사용)을 분류하는 방법을 완전히 확신하지 못하지만, 성능이 좋은 사람들보다 프로그래밍하기 쉬운 추상화를 사용하는쪽으로 방향을 바꾸는 것을 선호합니다. 프로파일 링을 사용하고 결과를 비교할 올바른 (빈번히 느리지 만) 참조 구현을 사용할 수있는 단계입니다.


7

당신이 말하는 것처럼 보이는 것은 해시 기반 조회 컨테이너를 사용하는 것과 같은 최적화와 많은 키 조회가 수행 될 때 배열과 같은 인덱싱 된 컨테이너를 사용하는 것입니다. 입니다 하지 조기 최적화,하지만 뭔가 당신은 설계 단계에서 결정해야합니다.

Knuth 규칙이 ​​사용하는 최적화 유형은 가장 일반적인 코드 경로의 길이를 최소화하고, 예를 들어 어셈블리에서 다시 작성하거나 코드를 단순화하여 덜 일반적으로 만드는 등 가장 많이 실행되는 코드를 최적화하는 것입니다. 그러나 이렇게하는 것은 코드의 어떤 부분이 이런 종류의 최적화가 필요한지 확신 할 때까지 아무 소용이 없습니다. 최적화는 코드를 이해하거나 유지하기 어렵게 만들 것입니다. 따라서 "조기 최적화는 모든 악의 근원"입니다.

Knuth는 또한 최적화하는 대신 프로그램이 사용하는 알고리즘, 문제에 대한 접근 방식을 변경하는 것이 항상 낫다고 말합니다. 예를 들어 약간 조정하면 최적화를 통해 속도가 10 % 증가 할 수 있지만 프로그램 작동 방식을 근본적으로 변경하면 10 배 더 빨라질 수 있습니다.

이 질문에 게시 된 다른 많은 댓글에 대한 반응으로 알고리즘 선택! = 최적화


7

데이터베이스 관점에서 최적의 설계를 설계 단계에서 고려하지 않는 것은 기껏해야 어리석은 일입니다. 데이터베이스는 쉽게 리팩터링되지 않습니다. 설계가 잘못되면 (최적화를 고려하지 않는 설계는 조기 최적화라는 말도 안되는 넌센스 뒤에 숨어도 상관없이) 데이터베이스가 너무 기본적이기 때문에 거의 복구 할 수 없습니다. 전체 시스템의 운영. 응용 프로그램 전체에서 커서를 사용했기 때문에 백만 명의 사용자와 사람들이 소리를지를 때까지 기다리는 것보다 예상되는 상황에 맞는 최적의 코드를 고려하여 올바르게 디자인하는 것이 훨씬 저렴합니다. sargeable 코드 사용, 가능한 최상의 인덱스 선택 등과 같은 기타 최적화는 디자인 타임에만 수행하는 것이 좋습니다. 빠르고 더러운 것을 그렇게 부르는 이유가 있습니다. 잘 작동하지 않기 때문에 빠른 코드를 좋은 코드 대신 사용하지 마십시오. 또한 솔직히 데이터베이스의 성능 튜닝을 이해하면 성능이 좋지 않은 코드를 작성하는 데 걸리는 시간보다 같은 시간에 잘 수행 될 가능성이 더 높은 코드를 작성할 수 있습니다. 좋은 성능의 데이터베이스 디자인을 배우는 데 시간을 할애하지 않는 것은 모범 사례가 아니라 개발자의 게으름입니다.


6

최대의 요점은 일반적으로 최적화가 복잡하고 복잡 하다는 것 입니다. 그리고 일반적으로 아키텍트 / 디자이너 / 프로그래머 / 유지 관리자는 무슨 일이 일어나고 있는지 이해하기 위해 명확하고 간결한 코드가 필요합니다.

특정 최적화가 명확하고 간결하다면 자유롭게 실험 해보세요 (하지만 돌아가서 최적화가 효과적인지 확인하세요). 요점은 성능의 이점이 최적화를 작성하고 유지하는 데 드는 비용을 능가 할 때까지 개발 프로세스 전반에 걸쳐 코드를 명확하고 간결하게 유지하는 것입니다.


2
실제로, 약간의 "최적화"는 작업에 적합한 알고리즘을 선택하는 것으로 귀결됩니다. 이는 높은 수준의 결과가있는 높은 수준의 활동입니다. Knuth 인용문의 "작은 효율성"과는 거리가 멀습니다.
Shog9

4

성능 문제가 확인 된 경우에만 최적화하려고합니다.

조기 최적화에 대한 나의 정의는 '성능 문제로 알려지지 않은 코드에 낭비되는 노력'입니다. 확실히 최적화를위한 시간과 장소가 있습니다. 그러나 비결은 애플리케이션의 성능에 영향을 미치고 추가 비용이 성능 저하보다 큰 경우에만 추가 비용을 지출하는 것입니다.

코드 (또는 DB 쿼리)를 작성할 때 '효율적인'코드 (즉, 의도 한 기능을 수행하는 코드, 합리적인 가장 단순한 논리로 빠르고 완벽하게 수행하는 코드)를 작성하려고 노력합니다. '효율적인'코드가 반드시 '최적화 된'코드와 동일하지는 않습니다. 암호. 최적화는 종종 코드에 추가 복잡성을 도입하여 해당 코드의 개발 및 유지 관리 비용을 모두 증가시킵니다.

내 조언 : 이점을 정량화 할 수있을 때만 최적화 비용을 지불하십시오.


4

프로그래밍 할 때 많은 매개 변수가 중요합니다. 이들 중 :

  • 가독성
  • 유지 보수성
  • 복잡성
  • 견고 함
  • 단정
  • 공연
  • 개발 시간

최적화 (성능을 추구)는 종종 다른 매개 변수를 희생하고 이러한 영역의 "손실"과 균형을 이루어야합니다.

잘 작동하는 잘 알려진 알고리즘을 선택할 수있는 옵션이 있으면 사전에 "최적화"하는 비용이 허용되는 경우가 많습니다.


1
위에 나열한 가장 중요한 QA 매개 변수 하나가 누락되었습니다. 요구 사항 충족. 소프트웨어가 의도 한 청중의 요구 사항을 충족하지 않으면 다른 모든 매개 변수는 의미가 없습니다. 성능이 만족스럽지 않으면 요구 사항이 충족되지 않은 것입니다.
SmacL

3
그것은 정확성으로 덮여 있다고 말할 수 있습니다. 게다가 '가능한 한 빨리'라는 의미의 '성능'은 요구 사항 중 매우 드물며 다른 요구와의 절충점이라는 Ola의 요점조차도 사실입니다.
frankodwyer

4

최적화는 매우 높은 수준에서 매우 낮은 수준까지 다양한 수준에서 발생할 수 있습니다.

  1. 좋은 아키텍처, 느슨한 결합, 모듈성 등으로 시작하십시오.

  2. 문제에 적합한 데이터 구조와 알고리즘을 선택하십시오.

  3. 메모리를 최적화하여 캐시에 더 많은 코드 / 데이터를 넣으십시오. 메모리 하위 시스템은 CPU보다 10 ~ 100 배 느리고 데이터가 디스크에 페이징되면 1000 ~ 10,000 배 느립니다. 메모리 소비에 대해주의를 기울이면 개별 명령어를 최적화하는 것보다 큰 이점을 얻을 수 있습니다.

  4. 각 함수 내에서 흐름 제어 문을 적절하게 사용합니다. (불변 표현식을 루프 본문 외부로 이동하십시오. 스위치 / 케이스 등에 가장 일반적인 값을 먼저 넣으십시오.)

  5. 각 문 내에서 올바른 결과를 산출하는 가장 효율적인 식을 사용하십시오. (곱하기 vs. 시프트 등)

나누기 식을 사용할지 아니면 시프트 식을 사용할 지에 대한 간단한 선택이 반드시 조기 최적화 는 아닙니다 . 아키텍처, 데이터 구조, 알고리즘, 메모리 공간 및 흐름 제어를 먼저 최적화하지 않고 그렇게하는 경우에는 시기상조입니다.

물론 목표 성능 임계 값을 정의하지 않으면 모든 최적화가 시기상조입니다.

대부분의 경우 다음 중 하나입니다.

A) 높은 수준의 최적화를 수행하여 목표 성능 임계 값에 도달 할 수 있으므로 표현식을 조작 할 필요가 없습니다.

또는

B) 가능한 모든 최적화를 수행 한 후에도 목표 성능 임계 값을 충족하지 못하며 낮은 수준의 최적화는 가독성 손실을 정당화하기에 충분한 성능 차이를 만들지 않습니다.

내 경험상 대부분의 최적화 문제는 아키텍처 / 디자인 또는 데이터 구조 / 알고리즘 수준에서 해결할 수 있습니다. 메모리 풋 프린트에 대한 최적화는 종종 (항상은 아니지만) 요구됩니다. 그러나 흐름 제어 및 표현 논리를 최적화 할 필요는 거의 없습니다. 그리고 실제로 필요한 경우에는 거의 충분하지 않습니다.


3

극단적 인 경우에는 프로파일 러를 사용할 필요가 없습니다. 프로젝트의 엔지니어는 성능 병목이 어디에 있는지 알고 있어야합니다.

"조기 최적화"는 엄청나게 주관적이라고 생각합니다.

일부 코드를 작성 중이고 Hashtable을 사용해야한다는 것을 알고 있다면 그렇게 할 것입니다. 결함이있는 방식으로 구현하지 않고 한 달 또는 1 년 후 누군가 문제가있을 때 버그 보고서가 도착할 때까지 기다립니다.

재 설계는 처음부터 명백한 방법으로 설계를 최적화하는 것보다 비용이 많이 듭니다.

분명히 처음에는 몇 가지 사소한 것들이 놓칠 수 있지만 이것이 핵심적인 디자인 결정은 거의 없습니다.

따라서 디자인을 최적화하지 않는 것은 IMO 자체가 코드 냄새입니다.


문제는 결코 문제가되지 않을 것이라고 생각했던 코드 섹션에서 병목 현상이 종종 발생한다는 것입니다. 프로파일 링은 가식없이 프로그램의 실제 비용 센터를 보여줍니다. 처음부터 분명한 일을하는 것이 가장 좋지만 그 밖의 모든 작업에는 프로파일 링이 있습니다.
Chris Smith

2

Norman의 대답은 훌륭합니다. 어떻게 든, 당신은 일상적으로 몇 가지 "조기 최적화"를 수행합니다. 실제로는 모범 사례입니다. 그렇지 않으면 완전히 비효율적 인 것으로 알려져 있기 때문입니다.

예를 들어, Norman의 목록에 추가하려면 :

  • 루프에서 String + String 대신 Java (또는 C # 등)에서 StringBuilder 연결 사용
  • 다음과 같이 C에서 루프를 피하는 것을 피 for (i = 0; i < strlen(str); i++)하십시오 : (여기서 strlen은 매번 문자열을 걷는 함수 호출이기 때문에 각 루프에서 호출됩니다);
  • 대부분의 자바 스크립트 구현에서 보이지만 더 빠르며 for (i = 0 l = str.length; i < l; i++)여전히 읽을 수 있으므로 괜찮습니다.

등등. 그러나 이러한 마이크로 최적화는 코드의 가독성을 희생해서는 안됩니다.


2

Knuth의 원래 인용문은 goto핫스팟을 제거하기위한 방법으로 신중하게 선택되고 측정 된 영역에서 사용을 권장하는 논문에서 나왔다는 점은 주목할 가치가 있습니다. 그의 인용문은 goto중요한 루프의 속도를 높이기 위해 사용 하는 이유를 정당화 하기 위해 추가 한 경고였습니다 .

[...] 다시 말하지만, 이것은 n의 평균값이 약 20이고 검색 루틴이 프로그램에서 약 백만 번 수행되는 경우 전체 실행 속도에서 눈에 띄게 절약됩니다. 이러한 루프 최적화 [사용 gotos]는 배우기가 어렵지 않으며 제가 말했듯이 프로그램의 작은 부분에만 적합하지만 종종 상당한 비용을 절감합니다. [...]

그리고 계속 :

오늘날 많은 소프트웨어 엔지니어들이 공유하는 통념은 소규모의 효율성을 무시할 것을 요구합니다. 그러나 나는 이것이 "최적화 된"프로그램을 디버깅하거나 유지할 수없는 어리석은 어리석은 프로그래머들에 의해 실행되고 있다고 보는 남용에 대한 과잉 반응이라고 믿는다. 기존 엔지니어링 분야에서 쉽게 얻을 수있는 12 % 개선은 한계로 간주되지 않습니다. 소프트웨어 엔지니어링에서도 같은 관점이 우세해야한다고 생각합니다. 물론 나는 일회성 작업에서 그러한 최적화를 수행하는 것을 귀찮게하지 않을 것입니다. 그러나 그것이 양질의 프로그램을 준비하는 문제 일 때, 그러한 효율성을 부정하는 도구에 제 자신을 제한하고 싶지 않습니다 [즉, goto 이 맥락에서 진술].

그가 따옴표 안에 "최적화"를 어떻게 사용했는지 기억하십시오 (소프트웨어가 실제로 효율적이지 않을 수 있음). 또한 그가 어떻게 "돈이 많고 어리석은"프로그래머들을 비판하는 것이 아니라, 당신이 작은 비 효율성을 항상 무시해야한다고 제안함으로써 반응하는 사람들도 주목하십시오. 마지막으로 자주 인용되는 부분 :

효율성의 성배가 남용으로 이어진다는 것은 의심의 여지가 없습니다. 프로그래머는 프로그램의 중요하지 않은 부분의 속도에 대해 생각하거나 걱정하는 데 막대한 시간을 낭비하며 이러한 효율성 시도는 실제로 디버깅 및 유지 관리를 고려할 때 강력한 부정적인 영향을 미칩니다. 97 % 정도의 작은 효율성은 잊어 버려야합니다. 조기 최적화는 모든 악의 근원입니다.

... 그리고 프로파일 링 도구의 중요성에 대해 더 알아보세요.

측정 도구를 사용해 온 프로그래머의 보편적 인 경험이 직관적 인 추측이 실패했기 때문에 프로그램의 어떤 부분이 정말 중요한지에 대해 사전에 판단하는 것은 종종 실수입니다. 7 년 동안 이러한 도구로 작업 한 후, 지금부터 작성된 모든 컴파일러는 모든 프로그래머에게 프로그램의 어떤 부분이 가장 비용이 많이 드는지 나타내는 피드백을 제공하도록 설계되어야한다고 확신했습니다. 실제로이 피드백은 특별히 꺼져 있지 않는 한 자동으로 제공되어야합니다.

사람들은 그의 말을 곳곳에서 오용 해 왔으며, 그의 논문 전체가 마이크로 최적화를 옹호 할 때 마이크로 최적화가 시기상조라고 제안하는 경우가 많습니다! 그가 항상 작은 효율성을 무시하면서이 "통상적 인 지혜"를 반영하는 그가 비판했던 사람들 중 하나는 원래 모든 형태의 마이크로 최적화를 방해하는 그러한 유형에 대해 부분적으로는 부분적으로 지시 된 그의 인용문을 종종 오용하고 있습니다. .

그러나 프로파일 러를 들고있는 숙련 된 손이 사용할 때 적절하게 적용된 마이크로 최적화 를 찬성하는 인용문이었습니다 . 처럼 오늘날의 유비 상당 수 있습니다 "사람들은 자신의 소프트웨어를 최적화하는 맹인의 찌르기를 복용하지 않아야하지만, 참조의 지역성을 개선하기 위해 핵심 분야에 적용 할 때 사용자 정의 메모리 할당 자는 큰 차이를 만들 수있다" 또는 " 필기 SIMD 코드는을 사용하여 SoA 담당자는 유지 관리가 정말 어렵고 모든 곳에서 사용해서는 안되지만 숙련되고 안내 된 손이 적절하게 적용하면 메모리를 훨씬 더 빨리 소비 할 수 있습니다. "

Knuth가 위에서 홍보 한대로 신중하게 적용된 마이크로 최적화를 홍보하려고 할 때마다 초보자가 .NET을 사용하기 위해 전체 소프트웨어를 다시 작성하는 것과 같이 너무 흥분하고 맹목적으로 최적화에 찌르는 것을 막기 위해 면책 조항을 던지는 것이 좋습니다 goto. 그게 부분적으로 그가하고 있었던 일입니다. 그의 말은 사실상 큰 면책 조항의 일부였습니다. 마치 누군가가 불타는 불 구덩이에서 오토바이 점프를하는 것처럼 아마추어가 집에서 이것을 시도해서는 안된다는 면책 조항을 추가하는 동시에 적절한 지식과 장비없이 시도하고 다치는 사람들을 비판 할 수 있습니다. .

그가 "조기 최적화"라고 생각한 것은 자신이하는 일을 효과적으로 알지 못하는 사람들이 적용한 최적화였습니다. 최적화가 정말 필요한지 몰랐고, 적절한 도구로 측정하지 않았고, 아마도 그 특성을 이해하지 못했을 것입니다. 그들의 컴파일러 또는 컴퓨터 아키텍처, 그리고 무엇보다도 "엄청나게 어리석은"것이 었습니다. 즉, 동전을 꼬집음으로써 최적화 (수백만 달러를 절약) 할 수있는 큰 기회를 간과했습니다. 더 오래 효과적으로 디버그하고 유지합니다.

만약 당신이 "pennywise-and-pound-foolish"카테고리에 맞지 않는다면, 당신이 goto중요한 루프의 속도를 높이기 위해 a 를 사용하고 있더라도 Knuth의 표준에 의해 너무 일찍 최적화되지 않는 것입니다. 오늘날의 옵티 마이저에 대한 많은 도움이 될 수 있지만, 만약 그렇게된다면 진정으로 중요한 영역에서는 너무 일찍 최적화하지 않을 것입니다). 진정으로 필요한 영역에 실제로 무엇을하든 적용하고 있으며 진정으로 혜택을받는다면 Knuth의 눈에는 훌륭한 일을하고있는 것입니다.


1

저에게 조기 최적화는 작동하는 시스템을 갖기 전에, 그리고 실제로 프로파일 링하고 병목이 어디에 있는지 알기 전에 코드의 효율성을 향상시키려는 것을 의미합니다. 그 이후에도 가독성과 유지 보수성은 많은 경우 최적화보다 우선해야합니다.


1

인정 된 모범 사례가 조기 최적화라고 생각하지 않습니다. 사용 시나리오에 따라 잠재적 인 성능 문제인 what ifs에 대한 굽기 시간에 관한 것입니다. 좋은 예 : 병목 현상이 있다는 증거를 얻기 전에 물체에 대한 반사를 최적화하려고 노력한다면 너무 일찍 최적화하는 것입니다.


1

사용자 또는 비즈니스 요구 사항으로 인해 애플리케이션에서 더 많은 성능이 필요하다는 사실을 발견하지 않는 한 최적화에 대해 걱정할 이유가 거의 없습니다. 그래도 코드를 프로파일 링 할 때까지 아무것도하지 마십시오. 그런 다음 가장 많은 시간이 걸리는 부분을 공격하십시오.


0

내가 보는 방식은 다른 시나리오에서 얼마나 많은 성능을 얻을 수 있는지 알지 못하고 무언가를 최적화하는 경우 조기 최적화입니다. 코드의 목표는 실제로 인간이 읽기 쉽게 만들어야합니다.


0

비슷한 질문에 대해 게시했듯이 최적화 규칙은 다음과 같습니다.

1) 최적화하지 마십시오

2) (전문가 전용) 나중에 최적화

최적화가 시기상조입니까? 보통.

예외는 아마도 디자인이나 많이 사용되는 잘 캡슐화 된 코드에있을 수 있습니다. 과거에 저는 컴파일러가 생성 한 어셈블러를 살펴보고 내부 루프에서 불필요한 명령어 하나를 제거하면 시간이 중요한 코드 (RSA 구현)를 작업 한 적이 있습니다. 그러나 더 정교한 알고리즘을 사용하여 속도가 빨라진 것은 그보다 훨씬 더 많았습니다.

최적화 할 때 스스로에게 물어볼 또 다른 질문은 "여기에서 300 보드 모뎀을 최적화하는 것과 동일한 작업을 수행하고 있습니까?"입니다. . 즉, 무어의 법칙이 너무 오래 지나지 않아 최적화를 무의미하게 만들 것입니다. 확장의 많은 문제는 더 많은 하드웨어를 문제에 던져서 해결할 수 있습니다.

마지막으로 프로그램이 너무 느리게 진행되기 전에 최적화하는 것은 시기상조입니다. 웹 애플리케이션 인 경우로드 상태에서 실행하여 병목 지점을 확인할 수 있습니다.하지만 대부분의 다른 사이트와 동일한 확장 문제가 발생하고 동일한 솔루션이 적용될 가능성이 있습니다.

편집 : 덧붙여서, 링크 된 기사와 관련하여 많은 가정에 의문을 제기합니다. 첫째, 무어의 법칙이 90 년대에 중단되었다는 것은 사실이 아닙니다. 둘째, 사용자의 시간이 프로그래머의 시간보다 더 중요하다는 것이 분명하지 않습니다. 대부분의 사용자는 (최소한) 어쨌든 사용 가능한 모든 CPU 사이클을 미친 듯이 사용하지 않으며 네트워크가 무언가를 수행하기를 기다리고있을 것입니다. 또한 프로그래머의 시간이 다른 것을 구현하는 것에서 사용자가 전화를하는 동안 프로그램이 수행하는 작업을 몇 밀리 초 단축하는 것으로 전환 될 때 기회 비용이 발생합니다. 그보다 긴 것은 일반적으로 최적화가 아니라 버그 수정입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.