성능을 향상시키기 위해 어떤 간단한 기술을 사용하십니까?


21

코드를 읽기 어렵게 만들지 않고 성능을 향상시키기 위해 간단한 루틴을 작성하는 방법에 대해 이야기하고 있습니다.

for(int i = 0; i < collection.length(); i++ ){
   // stuff here
}

그러나 일반적으로 a foreach가 적용되지 않는 경우이 작업을 수행합니다 .

for(int i = 0, j = collection.length(); i < j; i++ ){
   // stuff here
}

나는 이것이 length한 번만 메소드 를 호출하기 때문에 이것이 더 나은 접근법이라고 생각한다 . 자신의 개발에 사용하는 다른 간단한 트릭이 있습니까?


34
코드가 명확하지 않을 때 알려줄 여자 친구를 위해 +1하십시오.
Kristo

76
당신은 여자 친구가 있다고 알려주기 위해 이것을 게시하고 있습니다.
Josh K

11
@Christian :이 작업을 수행 할 수있는 컴파일러 최적화가 있다는 것을 잊지 마십시오. 따라서 가독성에만 영향을 미치고 성능에는 전혀 영향을 미치지 않을 수 있습니다. 조기 최적화는 모든 악의 근원입니다 ... 같은 줄에 둘 이상의 선언이나 과제를 피하고 사람들이 두 번 읽지 않도록하십시오 ... 일반적인 방법 (첫 번째 예)을 사용하거나 for 루프 외부의 두 번째 선언 (j이 의미하는 것을 읽기 위해 다시 읽어야하기 때문에 가독성이 감소하지만).
Tamara Wijsman

5
@TomWij : 올바른 (그리고 완전한) 인용문 : "우리는 시간의 97 % 정도의 작은 효율성을 잊어야합니다. 조기 최적화는 모든 악의 근원입니다. 그러나 우리는 그 중요한 3 %의 기회를 포기해서는 안됩니다. "
Robert Harvey

3
@tomwij : 만약 당신이 3 %를 소비한다면, 정의상 당신은 시간에 중요한 코드로해야하고 다른 97 %에 시간을 낭비하지 않아야합니다.
Robert Harvey

답변:


28

조기 토론은 모든 사악한 근본 강의 삽입

즉, 불필요한 효율성을 피하기 위해 얻은 습관이 있으며 경우에 따라 코드를 더 간단하고 정확하게 만들 수 있습니다.

이것은 일반적인 원칙에 대한 논의가 아니라 불필요한 비효율적 인 코드 도입을 피하기 위해 알아야 할 사항입니다.

당신의 큰 O를 알고

이것은 아마도 위의 긴 토론에 병합되어야합니다. 내부 루프가 계산을 반복하는 루프 내부의 루프가 느리다는 것은 매우 상식입니다. 예를 들면 다음과 같습니다.

for (i = 0; i < strlen(str); i++) {
    ...
}

루프가 반복 될 때마다 길이가 다시 계산되기 때문에 문자열이 실제로 길면 끔찍한 시간이 걸립니다. 참고 GCC가 있기 때문에 실제로이 사건을 최적화 strlen()순수 함수로 표시됩니다.

백만개의 32 비트 정수를 정렬 할 때 버블 정렬은 잘못된 방법입니다 . 일반적으로 정렬은 O (n * log n) 시간 (또는 기수 정렬의 경우 더 나은)으로 수행 할 수 있으므로 데이터가 작을 것 같지 않다면 적어도 O (n) 인 알고리즘을 찾으십시오. * 로그 n).

마찬가지로 데이터베이스를 다룰 때 인덱스를 알고 있어야합니다. 당신이 경우 SELECT * FROM people WHERE age = 20, 당신은 사람에 대한 인덱스 (나이)이없는, 그것이 O (N)가 필요합니다 순차 검색보다는 훨씬 빠른 O (로그 n)이 인덱스 스캔보다.

정수 산술 계층

C로 프로그래밍 할 때는 일부 산술 연산이 다른 연산보다 비싸다는 것을 명심하십시오. 정수의 경우 계층 구조는 다음과 같습니다 (최소한 비싸지 않음).

  • + - ~ & | ^
  • << >>
  • *
  • /

부여, 컴파일러는 같은 일반적으로 최적화 일 것이다 n / 2n >> 1자동으로 주류 컴퓨터를 대상으로하는 경우,하지만 당신은 임베디드 장치를 대상으로하는 경우, 당신은 그 고급 스러움을 얻을 수 있습니다.

또한, % 2& 1다른 의미를 갖는다. 나눗셈과 계수는 일반적으로 0으로 반올림되지만 구현이 정의되었습니다. 좋은 ol ' >>이며 &항상 부정적인 무한대로 반올림합니다. 제 의견으로는 훨씬 더 의미가 있습니다. 예를 들어, 내 컴퓨터에서 :

printf("%d\n", -1 % 2); // -1 (maybe)
printf("%d\n", -1 & 1); // 1

따라서 말이되는 것을 사용하십시오. % 2처음에 글을 쓸 때 사용하여 좋은 소년이라고 생각하지 마십시오 & 1.

비싼 부동 소수점 연산

같은 부동 소수점 연산 않도록 무거운 pow()log()정수 처리 특히 정말 그들을 필요로하지 않는다 코드. 예를 들어 숫자를 읽으십시오.

int parseInt(const char *str)
{
    const char *p;
    int         digits;
    int         number;
    int         position;

    // Count the number of digits
    for (p = str; isdigit(*p); p++)
        {}
    digits = p - str;

    // Sum the digits, multiplying them by their respective power of 10.
    number = 0;
    position = digits - 1;
    for (p = str; isdigit(*p); p++, position--)
        number += (*p - '0') * pow(10, position);

    return number;
}

이러한 사용 pow()(및이 를 사용하는 데 필요한 int<-> double변환)은 비용이 많이들뿐만 아니라 정밀 손실의 기회를 만듭니다 (실수로 위의 코드에는 정밀도 문제가 없습니다). 이것이 수학적이지 않은 상황에서 이러한 유형의 함수가 사용되는 것을 볼 때 나는이기는 이유입니다.

또한, 각 반복마다 10을 곱한 아래의 "영리한"알고리즘이 실제로 위의 코드보다 어떻게 더 간결한 지 확인하십시오.

int parseInt(const char *str)
{
    const char *p;
    int         number;

    number = 0;
    for (p = str; isdigit(*p); p++) {
        number *= 10;
        number += *p - '0';
    }

    return number;
}

매우 철저한 답변.
Paddyslacker

1
조기 최적화 토론은 가비지 코드에는 적용되지 않습니다. 항상 처음부터 잘 작동하는 구현을 사용해야합니다.

strlen ()이 순수한 함수로 표시되어 있기 때문에 GCC는 실제로이 경우를 최적화합니다. 나는 그것이 순수한 것이 아니라 const 함수라는 것을 의미한다고 생각합니다.
Andy Lester

@ 앤디 레스터 : 사실, 나는 순수한 것을 의미했습니다. GCC 문서 에서는 const 함수가 전역 메모리를 읽을 수 없다는 점에서 const가 pure보다 약간 더 엄격하다고 명시하고 있습니다. strlen()포인터 인수가 가리키는 문자열을 검사하므로 const가 될 수 없습니다. 또한, strlen()사실의 glibc의 순수로 표시됩니다string.h
조이 아담스

네 말이 맞아, 내 실수, 나는 다시 한 번 확인해야했다. 나도 같이 앵무새 프로젝트 주석 기능에 일한지 pure또는 const심지어 때문에 둘 사이의 미묘한 차이 헤더 파일을 문서화. docs.parrot.org/parrot/1.3.0/html/docs/dev/c_functions.pod.html
Andy Lester

13

귀하의 질문과 의견 스레드 에서이 코드 변경으로 성능이 향상된다는 것을 "생각"하는 것처럼 들리지만 실제로는 그렇지 않은지 알 수 없습니다.

저는 Kent Beck의 철학을 좋아합니다 .

"작동하게하고, 올바르게 만들고, 빠르게 만드십시오."

코드 성능을 향상시키는 내 기술은 먼저 코드를 단위 테스트를 통과하고 잘 팩토링 한 다음 (특히 루핑 작업의 경우) 성능을 확인하는 단위 테스트를 작성한 다음 코드를 리팩터링하거나 다른 알고리즘을 생각합니다. 선택한 ve가 예상대로 작동하지 않습니다.

예를 들어, .NET 코드로 속도를 테스트하기 위해 NUnit의 Timeout 속성 을 사용 하여 특정 메소드에 대한 호출이 특정 시간 내에 실행될 것이라는 주장을 작성합니다.

NUnit의 timeout 속성과 같은 코드 예제 (루프에 대한 많은 반복)를 사용하면 코드에 대한 "개선"이 실제로 해당 루프의 성능에 도움이되었는지 여부를 실제로 입증 할 수 있습니다.

한 가지 면책 조항 : 이는 "마이크로"수준에서 효과적이지만 성능을 테스트하는 유일한 방법은 아니며 "매크로"수준에서 발생할 수있는 문제를 고려하지는 않지만 좋은 시작입니다.


2
필자는 프로파일 링에 대한 큰 신자이지만 Cristian이 찾고있는 여러 가지 팁을 염두에 두는 것이 현명하다고 생각합니다. 나는 항상 똑같이 읽을 수있는 두 가지 방법 중 빠른 것을 선택합니다. 미성숙 후 최적화에 빠지는 것은 재미가 없습니다.
AShelly

반드시 단위 테스트가 필요하지는 않지만, 항상 20 분을 사용하여 성능에 관한 신화가 참인지 아닌지를 확인하는 것이 좋습니다. 특히 답변은 종종 컴파일러와 -O 및 -g 플래그 상태 (또는 디버그 / VS의 경우 출시).
mbq

+1이 답변은 내 관련 의견을 질문 자체에 보완합니다.
Tamara Wijsman

1
@ AShelly : 루프 구문의 간단한 재구성에 대해 이야기하고 있다면 사실 후에 변경하는 것이 매우 쉽습니다. 또한 다른 프로그래머에게는 동일하게 읽을 수있는 내용이 없을 수도 있습니다. "표준"구문을 최대한 사용하는 것이 가장 좋으며 필요한 경우에만 구문을 변경하십시오.
Joeri Sebrechts

@AShelly 확실히 당신이 읽을 수있는 두 가지 방법을 생각할 수 있고 당신이 일을하지 않는 덜 효율적인 방법을 선택한다면? 누구든지 실제로 그렇게 하시겠습니까?
glenatron

11

컴파일러가 다음을 잘 돌릴 수 있음을 명심하십시오.

for(int i = 0; i < collection.length(); i++ ){
   // stuff here
}

으로:

int j = collection.length();
for(int i = 0; i < j; i++ ){
   // stuff here
}

또는 collection루프에서 변경되지 않은 경우 비슷한 것 입니다.

이 코드가 응용 프로그램의 시간 결정적인 섹션에있는 경우 이것이 사실인지 아닌지 또는 실제로이를 위해 컴파일러 옵션을 변경할 수 있는지 여부를 알아볼 가치가 있습니다.

이렇게하면 코드의 가독성이 유지되며 (전자는 대부분의 사람들이 볼 것으로 예상되는 것처럼) 몇 번의 추가 기계 사이클을 얻습니다. 그러면 컴파일러가 도와 줄 수없는 다른 영역에 자유롭게 집중할 수 있습니다.

참고 사항 : collection요소를 추가하거나 제거하여 루프 내부 를 변경하면 (예, 나쁜 생각이지만 발생합니다) 두 번째 예제는 모든 요소를 ​​반복하지 않거나 과거에 액세스하려고 시도합니다 배열의 끝


1
왜 명시 적으로하지 않습니까?

3
경계를 검사하는 일부 언어에서는 명시 적으로 코드를 작성하면 코드가 느려집니다. collection.length에 대한 루프를 사용하면 컴파일러가이를 제거하고 경계 검사를 생략합니다. 앱의 다른 곳에서 일부 상수로 루프하면 모든 반복에 대한 경계 검사가 있습니다. 그렇기 때문에 측정이 중요합니다. 성능에 대한 직관은 거의 맞지 않습니다.
Kate Gregory

1
그렇기 때문에 "알아 볼 가치가 있습니다"라고 말했습니다.
ChrisF

C # 컴파일러는 collection.length ()가 stack.pop ()과 같은 방식으로 collection.length ()가 컬렉션을 수정하지 않는다는 것을 어떻게 알 수 있습니까? 컴파일러가 이것을 최적화한다고 가정하는 대신 IL을 확인하는 것이 가장 좋을 것이라고 생각합니다. C ++에서는 메소드를 const ( '객체를 변경하지 않음')로 표시 할 수 있으므로 컴파일러는이 최적화를 안전하게 수행 할 수 있습니다.
JBR 윌킨슨

1
@JBRW이 작업을 수행하는 최적화 프로그램은 컬렉션의 ok-let's-call-it-constness-그럼에도 불구하고 이것이 C ++이 아닌 메소드를 알고 있습니다. 결국 당신은 무언가가 컬렉션이라는 것을 알 수 있고 길이를 얻는 방법을 알고 있는지 경계 검사 만 할 수 있습니다.
Kate Gregory

9

이런 종류의 최적화는 일반적으로 권장되지 않습니다. 이 최적화는 컴파일러가 쉽게 수행 할 수 있으며 어셈블리 대신 더 높은 수준의 프로그래밍 언어로 작업하므로 동일한 수준에서 생각하십시오.


1
그녀에게 프로그래밍에 관한 책을 줘;)
Joeri Sebrechts

1
+1, 대부분의 여자 친구가 코드 선명도보다 Lady Gaga에 더 관심이있을 가능성이 높습니다.
haploid

권장하지 않는 이유를 설명해 주시겠습니까?
Macneil

@macneil 잘 ... 그 트릭은 코드를 그렇게 일반적이지 않고 완전히 작동하지 않게 만듭니다. 최적화는 컴파일러가 수행해야합니다.
tactoth

@macneil 고급 언어로 작업하는 경우 같은 수준으로 생각하십시오.
tactoth

3

이것은 범용 코딩에는 그다지 적용되지 않을 수 있지만 요즘에는 주로 임베디드 개발을 수행합니다. 우리는 특정 타겟 프로세서를 가지고 있습니다 (더 빨라지지는 않을 것입니다-20 년 이상 시스템을 폐기 할 때 기이하게 쓸모없는 것처럼 보일 것입니다). 프로세서는 모든 프로세서와 마찬가지로 어떤 작업이 빠르거나 느린 지에 대한 특정 문제가 있습니다.

우리는 전체 팀의 가독성을 유지하면서 가장 효율적인 코드를 생성하는 데 사용되는 기술을 보유하고 있습니다. 가장 자연스러운 언어 구성이 가장 효율적인 코드를 생성하지 않는 곳에 최적의 코드가 사용되도록 매크로를 만들었습니다. 다른 프로세서에 대한 후속 프로젝트를 수행하는 경우 해당 프로세서에서 최적의 방법으로 매크로를 업데이트 할 수 있습니다.

구체적인 예로, 현재 프로세서의 경우 분기는 파이프 라인을 비우고 프로세서를 8주기 동안 정지시킵니다. 컴파일러는 다음 코드를 사용합니다.

 bool isReady = (value > TriggerLevel);

그것을 다음과 같은 어셈블리로 바꿉니다.

isReady = 0
if (value > TriggerLevel)
{
  isReady = 1;
}

이 과정은 3주기 또는 10 회 이상 소요됩니다 isReady=1;. 그러나 프로세서에는 단일주기 max명령이 있으므로이 시퀀스를 생성하는 코드를 작성하는 것이 훨씬 좋습니다.

diff = value-TriggerLevel;
diff = max(diff, 0);
isReady = min(1,diff);

분명히, 여기의 의도는 원본보다 명확하지 않습니다. 그래서 우리는 부울 큰 비교를 원할 때마다 사용하는 매크로를 만들었습니다.

#define BOOL_GT(a,b) min(max((a)-(b),0),1)

//isReady = value > TriggerLevel;
isReady = BOOL_GT(value, TriggerLevel);

다른 비교를 위해 비슷한 일을 할 수 있습니다. 외부인에게는 자연적인 구조 만 사용했을 때보 다 코드가 읽기 쉽지 않습니다. 그러나 코드 작업에 약간의 시간을 소비하면 신속하게 명확 해지 며 모든 프로그래머가 자체 최적화 기술을 실험하게하는 것보다 훨씬 좋습니다.


3

글쎄, 첫 번째 조언은 코드에서 무슨 일이 일어나고 있는지 정확히 알 때까지 그러한 조기 최적화를 피하는 것입니다.

예를 들어 C #에서 컴파일러는 배열에 액세스 할 때 인덱스를 범위 검사 할 필요가 없다는 것을 알고 있으므로 배열의 길이를 반복하는 경우 코드를 최적화합니다. 배열 길이를 변수에 넣어서 최적화하려고하면 루프와 배열 사이의 연결이 끊어지고 실제로 코드가 훨씬 느려집니다.

미세 최적화를하려면 많은 리소스를 사용하는 것으로 제한됩니다. 약간의 성능 향상이있는 경우 가장 읽기 쉽고 유지 보수가 쉬운 코드를 사용해야합니다. 컴퓨터 작업이 시간이 지남에 따라 변화하는 방식으로, 지금 발견 한 것이 조금 더 빠르지 만 그렇게 유지되지 않을 수 있습니다.


3

나는 매우 간단한 기술을 가지고 있습니다.

  1. 코드를 작동시킵니다.
  2. 나는 속도를 테스트합니다.
  3. 빠르면 다른 기능을 위해 1 단계로 돌아갑니다. 느린 경우 병목 현상을 찾기 위해 프로파일 링합니다.
  4. 병목 현상을 해결합니다. 1 단계로 돌아갑니다.

이 프로세스를 우회하는 데 시간을 절약 할 수있는 시간이 많이 있지만 일반적으로 그러한 경우인지 알 수 있습니다. 확실하지 않은 경우 기본적으로이를 고수합니다.


2

단락을 활용하십시오.

if(someVar || SomeMethod())

코딩하는 데 시간이 오래 걸리고 다음과 같이 읽을 수 있습니다.

if(someMethod() || someVar)

그러나 시간이 지남에 따라 더 빨리 평가 될 것입니다.


1

6 개월 정도 기다리십시오. 상사가 모든 사람에게 새 컴퓨터를 사도록하십시오. 진심으로. 프로그래머 시간은 장기적으로 하드웨어보다 비쌉니다. 고성능 컴퓨터를 통해 코더는 속도에 대한 염려없이 간단한 방식으로 코드를 작성할 수 있습니다.


6
어 ... 고객이 보는 성능은 어떻습니까? 그들도 새로운 컴퓨터를 구입할만큼 부유합니까?
Robert Harvey

2
그리고 우리는 거의 성과 벽에 도달했습니다. 멀티 코어 계산이 유일한 방법이지만 대기해도 프로그램에서이를 사용할 수는 없습니다.
mbq

+1이 답변은 내 관련 의견을 질문 자체에 보완합니다.
Tamara Wijsman

3
수천 명 또는 수백만 명의 사용자가있을 때 하드웨어보다 프로그래밍 시간이 비싸지 않습니다. 프로그래머 시간은 사용자 시간보다 중요하지 않으므로 가능한 빨리 머리를 통해 얻으십시오.
HLGEM

1
좋은 습관을들이십시오. 그러면 프로그래머가 항상하는 것처럼 프로그래머 시간이 걸리지 않습니다.
도미니크 맥도넬

1

미리 너무 많이 최적화하지 마십시오. 최적화 할 때는 가독성에 대해 조금 덜 걱정하십시오.

불필요하게 복잡한 것 이상은별로 없지만, 복잡한 상황에 처할 때 복잡한 솔루션이 종종 필요합니다.

가장 명확한 방법으로 코드를 작성하는 경우 복잡한 변경시 코드가 변경된 이유를 설명하십시오.

그러나 특히 당신의 의미에, 나는 기본 접근법과 반대되는 부울을 수행하는 것이 종종 도움이된다는 것을 알았습니다.

for(int i = 0, j = collection.length(); i < j; i++ ){
// stuff here
}

될 수있다

for(int i = collection.length(); i > 0; i-=1 ){
// stuff here
}

"재료"부분을 적절히 조정하고 읽을 수있는 한 많은 언어로 제공됩니다. 그것은 대부분의 사람들이 그것을 먼저 생각한다고 생각하는 방식으로 문제에 접근하지 않습니다.

C #에서 예를 들면 다음과 같습니다.

        string[] collection = {"a","b"};

        string result = "";

        for (int i = 0, j = collection.Count() - 1; i < j; i++)
        {
            result += collection[i] + "~";
        }

다음과 같이 쓸 수도 있습니다 :

        for (int i = collection.Count() - 1; i > 0; i -= 1)
        {
            result = collection[i] + "~" + result;
        }

(예, 조인 또는 stringbuilder를 사용하여해야하지만 간단한 예를 만들려고합니다.)

따라하기 어려운 많은 트릭이 있지만 문자열의 재 할당 페널티를 피하거나 이진 모드에서 텍스트 파일을 읽는 것을 피하기 위해 오래된 vb에서 할당의 왼쪽 중간을 사용하는 것과 같이 모든 언어에 적용되지 않는 많은 트릭이 있습니다. 파일이 readtoend에 비해 너무 클 때 .net에서 버퍼링 페널티를 극복하십시오.

내가 생각할 수있는 유일한 다른 일반적인 경우는 부울 대수를 복잡한 조건에 적용하여 방정식을 단락 조건부의 이점을 활용하거나 복잡한 방향을 바꿀 수있는 더 좋은 기회로 바꾸는 것입니다. 중첩 된 if-then 또는 case 문을 완전히 방정식으로 설정합니다. 이 두 가지가 모두 작동하지는 않지만 시간을 크게 절약 할 수 있습니다.


이 솔루션,하지만 컴파일러는 가능성이 가장 일반적인 클래스 길이로 경고를 () 부호없는 형식 반환 뱉어
스테인

그러나 인덱스를 되 돌리면 반복 자체가 더 복잡해질 수 있습니다.
Tamara Wijsman

@ stijn 나는 그것을 쓸 때 c #을 생각하고 있었지만 아마도이 제안은 그 이유로 언어 특정 범주에 속할 수도 있습니다-편집을 참조하십시오 ... 그 위험을 감수하지 않습니다. // 물건이 일종의 스택 조작이라면 로직을 올바르게 되돌릴 수는 없지만 대부분의 경우 IMHO를주의 깊게 수행하면 혼란스럽지 않습니다.
Bill

네가 옳아; C ++에서는 여전히 '정상'루프를 선호하지만 반복에서 벗어난 length () 호출 (const size_t len ​​= collection.length (); for (size_t i = 0; i <len; ++ i) {}) 두 가지 이유 : '정상'순방향 계산 루프가 더 읽기 쉽고 이해하기 쉬우 며 (아마도 더 일반적이기 때문일 수 있음) 루프에서 불변 길이 () 호출을 가져옵니다.
stijn

1
  1. 윤곽. 우리도 문제가 있습니까? 어디에?
  2. 어떻게 든 IO와 관련된 90 %의 경우 캐싱을 적용하십시오 (그리고 아마도 더 많은 메모리를 얻습니다)
  3. CPU와 관련된 경우 캐싱을 적용하십시오.
  4. 성능이 여전히 문제라면, 우리는 간단한 기술의 영역을 떠났습니다.

1

좋은 컴파일러, 좋은 프로파일 러, 좋은 라이브러리 등 최고의 도구를 사용하십시오 . 알고리즘을 올바르게 얻거나 더 나은 방법으로 올바른 라이브러리를 사용하십시오. 사소한 루프 최적화는 작은 감자이며, 최적화 컴파일러만큼 똑똑하지 않습니다.


1

나에게 가장 간단한 방법은 일반적인 경우 사용 패턴이 [0, 64)의 범위에 맞지만 상한이없는 드문 경우가있을 때마다 가능한 경우 스택을 사용하는 것입니다.

간단한 C 예제 (이전) :

void some_hotspot_called_in_big_loops(int n, ...)
{
    // 'n' is, 99% of the time, <= 64.
    int* values = calloc(n, sizeof(int));

    // do stuff with values
    ...
    free(values);
}

그리고 후에 :

void some_hotspot_called_in_big_loops(int n, ...)
{
    // 'n' is, 99% of the time, <= 64.
    int values_mem[64] = {0}
    int* values = (n <= 64) ? values_mem: calloc(n, sizeof(int));

    // do stuff with values
    ...
    if (values != values_mem)
        free(values);
}

이러한 종류의 핫스팟이 프로파일 링에서 많이 발생하므로 다음과 같이 일반화했습니다.

void some_hotspot_called_in_big_loops(int n, ...)
{
    // 'n' is, 99% of the time, <= 64.
    MemFast values_mem;
    int* values = mf_calloc(&values_mem, n, sizeof(int));

    // do stuff with values
    ...

    mf_free(&values_mem);
}

위의 99.9 % 경우 할당되는 데이터가 충분히 작은 경우 스택을 사용하고 그렇지 않으면 힙을 사용합니다.

C ++에서는 SmallVector동일한 개념을 중심으로 하는 표준 호환 작은 시퀀스 ( 구현 과 유사)로 이것을 일반화했습니다 .

그것은 장대 한 최적화가 아니며 (예를 들어, 작업이 1.8 초까지 완료되는 데 3 초가 단축되었습니다) 적용하는 데 사소한 노력이 필요합니다. 코드 줄을 도입하고 두 줄을 변경하여 3 초에서 1.8 초 사이에 무언가를 얻을 수 있다면, 그러한 작은 벅에 아주 좋은 기회입니다.


0

애플리케이션에 큰 영향을 미치는 데이터에 액세스 할 때 수행 할 수있는 많은 성능 변경이 있습니다. 쿼리를 작성하거나 ORM을 사용하여 데이터베이스에 액세스하는 경우 사용하는 데이터베이스 백엔드에 대한 성능 조정 서적을 읽어야합니다. 성능이 저하 된 알려진 기술을 사용하고있을 가능성이 있습니다. 무지를 제외하고 이것을 할 이유가 없습니다. 이것은 조기 최적화가 아닙니다 (성능에 대해 걱정하지 않고 광범위하게 사용 되었기 때문에 이것을 말한 사람을 저주합니다). 이것은 좋은 디자인입니다.

SQL Server의 성능 향상에 대한 간단한 샘플 : 적절한 인덱스 사용, 커서 사용 방지-집합 기반 논리 사용, sargable where 절 사용, 뷰 위에 뷰를 쌓지 않고 필요한 것보다 많은 데이터를 반환하지 않음 필요한 것보다 많은 열은 상관 된 하위 쿼리를 사용하지 마십시오.


0

이것이 C ++ 인 경우 ++i보다는 습관을 가져야합니다 i++. ++i더 나쁘지 않을 것입니다. 이는 독립형 진술과 정확히 동일하며, 경우에 따라 성능이 향상 될 수 있습니다.

오프 코드에서 도움이 될 기존 코드를 변경할 가치는 없지만 들어가는 것이 좋습니다.


0

나는 조금 다른 것을 취했다. 여기에 오는 조언을 따르는 것만으로도 큰 차이가 없습니다. 수정해야 할 실수가 있고 수정해야 할 부분이 있기 때문입니다.

실수는 모든 사람이하는 방식으로 데이터 구조를 설계하는 것입니다. 즉, 중복 데이터와 많은 추상화 계층, 구조 전체에 전파되는 속성과 알림을 통해 일관성을 유지하려고합니다.

그런 다음 성능 조정 (프로파일 링)을 수행하고 여러 가지 방법으로주기주기 비용이 얼마나 많은 추상화 계층인지, 일관성을 유지하려고하는 구조 전체에 전파되는 특성 및 알림과 함께 여러 계층의 추상화 방법을 보여줍니다.

코드를 크게 변경하지 않고도 이러한 문제를 해결할 수 있습니다.

운이 좋으면 적은 데이터 구조가 더 좋으며 많은 메시지를 메시지와 밀접하게 유지하는 것보다 일시적인 불일치를 견딜 수있는 것이 좋습니다.

루프를 작성하는 방법은 루프와 전혀 관련이 없습니다.

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