IT

스위치가 다음과 같은 경우보다 빠른 이유

itgroup 2022. 10. 28. 20:51
반응형

스위치가 다음과 같은 경우보다 빠른 이유

많은 자바 서적들이 다음과 같이 기술하고 있다.switchif else진술.하지만 왜 스위치가 if보다 빠른지 어디에서도 알 수 없었습니다.

저는 둘 중에 하나를 골라야 하는 상황이 있어요.어느쪽이든 사용할 수 있습니다.

switch (item) {
    case BREAD:
        //eat Bread
        break;
    default:
        //leave the restaurant
}

또는

if (item == BREAD) {
    //eat Bread
} else {
    //leave the restaurant
}

항목을 고려하고 BREAD는 상수 int 값입니다.

위의 예에서 어떤 이 더 빠른지, 그 이유는 무엇입니까?

케이스가 많을 때 효율적인 스위치스테이트먼트 평가를 가능하게 하는 특수한 바이트 코드가 있기 때문입니다.

IF 스테이트먼트를 실장했을 경우는, 체크, 다음 구로의 점프, 체크, 다음 구로의 점프 등이 있습니다.스위치를 사용하면 JVM이 비교할 값을 로드하고 값 테이블을 반복하여 일치하는 값을 찾습니다. 이는 대부분의 경우 더 빠릅니다.

A switch은 아닙니다.if진술.많은 목록보다 더 잘 확장됩니다.if-else「」라고 하는 를 지정합니다.switch는 모든 값을 기반으로 검색을 수행할 수 있습니다.이라면 더 더 수 있습니다.

현재 JVM에는 2종류의 스위치바이트 코드가 있습니다.LookupSwitch 및 TableSwitch.

스위치 스테이트먼트의 각 케이스에는 정수 오프셋이 있습니다.이 오프셋이 연속(또는 큰 틈이 없는 거의 연속)인 경우(케이스 0: 케이스 1: 케이스 2 등), TableSwitch 가 사용됩니다.

오프셋이 큰 간격(케이스 0: 케이스 400: 케이스 93748: 등)으로 펼쳐져 있는 경우 LookupSwitch가 사용됩니다.

즉, TableSwitch는 가능한 값 범위 내의 각 값에 특정 바이트 코드오프셋이 주어지기 때문에 일정 시간 내에 실행된다는 점이 다릅니다.따라서 스테이트먼트에 오프셋 3을 지정하면 스테이트먼트는 올바른 브랜치를 찾기 위해3 앞으로 점프하는 것을 알고 있습니다.

조회 스위치는 이진 검색을 사용하여 올바른 코드 분기를 찾습니다.이 동작은 O(log n) 타임으로 실행됩니다.이것은 여전히 양호하지만, 최선은 아닙니다.

자세한 내용은 여기를 참조하십시오.JVM의 LookupSwitch와 TableSwitch의 차이점

어느 것이 가장 빠른지에 대해서는, 다음의 어프로치를 사용합니다.값이 연속 또는 거의 연속인 케이스가 3개 이상 있는 경우 항상 스위치를 사용하십시오.

케이스가 2개일 경우 if 문을 사용합니다.

그 외의 상황에서는 LookupSwitch의 바이너리 검색이 나쁜 시나리오에 도달할 수 있기 때문에 스위치가 더 빠를 가능성이 높지만 장담할 수는 없습니다.

또한 JVM은 코드에서 가장 핫한 분기를 첫 번째로 배치하려고 하는 문에 대해 JIT 최적화를 실행합니다.이를 분기 예측이라고 합니다.상세한 것에 대하여는, https://dzone.com/articles/branch-prediction-in-java 를 참조해 주세요.

당신의 경험은 다를 수 있습니다.JVM이 LookupSwitch에서 유사한 최적화를 실행하지 않는지는 모르겠지만 JIT 최적화를 신뢰하고 컴파일러를 능가하지 않는 방법을 배웠습니다.

따라서 패킷의 로드를 계획하고 있는 경우는, 메모리의 코스트가 그다지 높지 않고, 어레이의 처리도 매우 빠릅니다.또한 점프 테이블을 자동으로 생성하기 위해 스위치 문에 의존할 수 없기 때문에 점프 테이블의 시나리오를 직접 생성하는 것이 더 쉽습니다.다음 예에서 볼 수 있듯이 최대 255개의 패킷을 상정하고 있습니다.

아래 결과를 얻으려면 추상화가 필요합니다.어떻게 작동하는지는 설명하지 않겠습니다. 그러니 이해해주셨으면 합니다.

필요한 경우 패킷사이즈를 255로 설정하기 위해 업데이트했습니다(id < 0) | (id > length)의 경계체크를 실행할 필요가 있습니다.

Packets[] packets = new Packets[255];

static {
     packets[0] = new Login(6);
     packets[2] = new Logout(8);
     packets[4] = new GetMessage(1);
     packets[8] = new AddFriend(0);
     packets[11] = new JoinGroupChat(7); // etc... not going to finish.
}

public void handlePacket(IncomingData data)
{
    int id = data.readByte() & 0xFF; //Secure value to 0-255.

    if (packet[id] == null)
        return; //Leave if packet is unhandled.

    packets[id].execute(data);
}

C++에서 점프 테이블을 많이 사용하기 때문에 편집 기능 포인터 점프 테이블의 예를 보여 줍니다.이것은 매우 일반적인 예이지만 실행해 보니 올바르게 동작합니다.포인터를 NULL로 설정해야 합니다.C++는 Java와 같이 자동으로 이 작업을 수행하지 않습니다.

#include <iostream>

struct Packet
{
    void(*execute)() = NULL;
};

Packet incoming_packet[255];
uint8_t test_value = 0;

void A() 
{ 
    std::cout << "I'm the 1st test.\n";
}

void B() 
{ 
    std::cout << "I'm the 2nd test.\n";
}

void Empty() 
{ 

}

void Update()
{
    if (incoming_packet[test_value].execute == NULL)
        return;

    incoming_packet[test_value].execute();
}

void InitializePackets()
{
    incoming_packet[0].execute = A;
    incoming_packet[2].execute = B;
    incoming_packet[6].execute = A;
    incoming_packet[9].execute = Empty;
}

int main()
{
    InitializePackets();

    for (int i = 0; i < 512; ++i)
    {
        Update();
        ++test_value;
    }
    system("pause");
    return 0;
}

또한 내가 제기하고 싶은 또 다른 포인트는 유명한 Divide and Concer이다.따라서 255개의 어레이 아이디어를 최악의 경우 8개로 줄일 수 있습니다.

즉, 번거롭고 신속한 관리가 어려우며, 일반적으로 다른 방법이 더 낫지만 어레이로 인해 문제가 해결되지 않는 경우에 활용됩니다.사용 사례와 각각의 상황이 가장 잘 작동하는 시기를 파악해야 합니다.체크가 몇 개만 있으면 두 가지 방법을 모두 사용하지 않을 수 있습니다.

If (Value >= 128)
{
   if (Value >= 192)
   {
        if (Value >= 224)
        {
             if (Value >= 240)
             {
                  if (Value >= 248)
                  {
                      if (Value >= 252)
                      {
                          if (Value >= 254)
                          {
                              if (value == 255)
                              {

                              } else {

                              }
                          }
                      }
                  }
             }      
        }
   }
}

바이트 코드레벨에서는 서브젝트 변수는 Runtime에 의해 로드된 구조화된 .class 파일의 메모리주소에서 프로세서레지스터에 한 번만 로드되며, 이것은 스위치스테이트먼트에 있습니다.반면 if스테이트먼트에서는 코드 컴파일 DE에 의해 다른 jvm 명령어가 생성되며, 이를 위해서는 각 변수가 alt를 등록하기 위해 로드되어야 합니다.hough 변수는 다음 if-statement에서 사용되는 변수와 동일합니다.어셈블리 언어로 코딩하는 것을 알고 있다면 이것은 흔한 일입니다. Java 컴파일된 콕스는 바이트 코드 또는 직접 기계 코드가 아니지만, 여기서의 조건부 개념은 여전히 일관됩니다.설명할 때 더 깊은 전문성을 피하려고 노력했어요나는 내가 그 개념을 명확하고 불명료하게 했기를 바란다.감사해요.

언급URL : https://stackoverflow.com/questions/6705955/why-switch-is-faster-than-if

반응형