2010-05-12 3 views
17

하자 내가Switch 명령문의 대소 문자 순서가 성능을 변경할 수 있습니까?

switch(alphabet) { 

    case "f": 
     //do something 
     break; 

    case "c": 
     //do something 
     break; 

    case "a": 
     //do something 
     break; 

    case "e": 
     //do something 
     break; 

} 

다음과 같이 switch 문이 있다고 가정 해 지금은 Alphabet 전자를 갖는 빈도가 가장 높은 각각, c와 f 뒤에 알고 가정합니다. 그래서, 난 그냥 case 문 순서를 재구성 다음과 같이 그들을 만든 :

switch(alphabet) { 

    case "e": 
     //do something 
     break; 

    case "a": 
     //do something 
     break; 

    case "c": 
     //do something 
     break; 

    case "f": 
     //do something 
     break; 
} 

두 번째 switch 문이 처음 switch 문보다 빠를 수 있습니까? 그렇다면 내 프로그램에서이 문장을 여러 번 말하면 switch 진술이라고 부를 필요가 있다면 상당한 개선이 될 것입니까? 아니면 성능 향상을 위해 주파수 기술을 어떻게 사용할 수 있습니까?

+3

당신이 알고있는 가장 명확한 방법을 쓰고, 실제 시나리오로 프로파일을 작성하고, 필요한 곳을 최적화해야합니까? –

답변

20

당신이 염려해야 할 부분은 그리 많지 않습니다. 확실히 예측할 수있는 것이 아닙니다.

문자열 케이스 레이블을 사용하면 컴파일러는 실제 문자열을 점프 테이블의 인덱스에 매핑하는 내부 해시 테이블을 사용합니다. 따라서 레이블의 수에 관계없이 연산은 실제로 O (1)입니다.

정수 레이블의 경우 생성되는 실제 코드는 레이블 수와 숫자가 연속 (또는 "거의"연속)인지 여부에 달려 있다고 생각합니다. 연속 된 경우 (1, 2, 3, 4, ...) 점프 테이블로 변환됩니다. 그 중 많은 수가있는 경우 문자열과 같이 Hashtable + 점프 테이블이 사용됩니다. 레이블이 몇 개 있고 점프 테이블로 즉시 변환 할 테이블이 아닌 경우 만 입력하면은 일련의 if..then..else 문으로 변환됩니다.

일반적으로 코드를 작성하여으로 읽을 수 있으므로 컴파일러가 "빠른"코드를 생성 할 수 없습니다.

(주 내 설명은 위의 C# 컴파일러가 내부적으로 어떻게 작동하는지의 구현 세부 사항은 다음과 같습니다 당신이 그런 식으로 작업이 항상에 의존해서는 안 - 사실, 그것도 바로 지금 처럼 작동하지 않을 수 있습니다 , 적어도 그것은 일반적인 생각이다).

+0

+1 : 내가 말하려고했던 것. 이것들은 GOTO (확인을위한 반사경 확인)로 구현됩니다. 그것은 O (1)입니다. - 그 시점에서 최적화에 대해 정말로 걱정할 필요는 없습니다 ... – Khanzor

+2

-1의 모든 것은 무엇입니까? –

+3

+1. perf가 ** 정말 ** 문제인 경우 금속에 더 가까운 언어를 사용하는 것이 좋습니다. –

-1

나는 스위치 케이스가 어떻게하면 매치를 찾기 위해 위에서 아래로 모든 케이스를 반복 할 것이라고 생각한다. 일치하면 거기에서 멈 춥니 다.

따라서 빈도 케이스의 우선 순위를 변경 한 경우 대답은 '예'입니다. 이는 성능 향상에 도움이 될 수 있습니다. 그러나 그것이 도움이되지 않을 것이라고 나는 믿는다.

1

상대적으로 작은 값 집합에 대해 동일한 성능을 나타냅니다. 이전에 C 프로그램의 어셈블리 코드를 검사 해 보았습니다. 컴파일러는 switch 문에있는 모든 값에서 점프 테이블을 만듭니다.

케이스 값이 너무 많으면 ifelse if으로 퇴화 할 것이므로 내기를 'E'에 놓으면 확실하게 속도가 빨라집니다.

C#의 경우 applicable이기도하지만 인접한 값만 사용하더라도 작은 집합으로 switch 문에 대한 점프 테이블을 생성합니다. 따라서 O (1)이기 때문에 첫 번째 값이 일치하지 않아도 여러 테스트가 없습니다.

2

이것은 컴파일러가 switch 문을 구현하는 방법에 따라 다릅니다.

먼저 임의로 순서를 바꿀 수는 없습니다. 하나의 케이스 블록 이 C와 유사한 언어 (C, C++, C#, Java, ...)로되어 있고 케이스 블록이 으로 끝나지 않으면 이 없기 때문에 케이스를 재정렬 할 수 없습니다 중단은 컴파일러가 다음 사례로 넘어가도록 구현해야 함을 의미합니다. 이 특수한 상황을 무시하면 나머지 경우를 다른 것으로 바꿀 수 있습니다.

경우 수가 적 으면 컴파일러에서 일련의 비교를 통해 사례 테스트 을 구현할 수 있습니다. 케이스의 수가 적 으면, 케이스로부터 균등 한 이진 트리 을 생성 할 수 있습니다. 대소 문자가 큰 경우 대부분 컴파일러는 밀도 집합 인 경우 스위치 값에 대해 인덱싱 된 분기를 구현합니다. 대소 문자 집합의 일부가 고밀도이고 부분이 이 아닌 경우 컴파일러에서 이진 트리 을 사용하여 사례를 그룹으로 분할하여 밀도가 높은 집합 및 밀도가 높은 집합 내에서 인덱싱 된 점프를 선택할 수 있습니다. (사실, 컴파일러는 적절한 경우로 제어를에 전달하는 모든 작업을 수행 할 수 있지만 가장 자주 위의 작업 중 하나입니다).

스위치를 구현하는 방법에 따라 순서가 중요 할 수도 있고 그렇지 않을 수도 있습니다. 대부분의 좋은 컴파일러는별로 중요하지 않습니다.

+1

명확성을 위해 질문은 C#으로 태그가 지정되어 있고 C#에서는 첫 번째 단락에 설명 된대로 폴링 사례를 지원하지 않습니다 (각 사례는 'break' 또는'return'으로 끝나야합니다). – Dusty

+0

흥미 롭습니다. 그래서 사람들은 불필요하게 C#에서 "break"를 코딩하고 있습니다 (예를 들어 OP의 예 참조). 정말 내 대답을 많이 바꾸지 않습니다. –

+0

아니요, C#은이 문제에 대해 약간 장황합니다. 명시 적으로 사례 블록을 종료해야합니다. 'break' (또는'return')이 필요합니다 (추후 변경 사항이 미래에 구현되어야하는 경우). 그리고 나는 동의합니다, 당신의 대답은 여전히 ​​정확하고 유용합니다. – Dusty

관련 문제