C#에서 상태 시스템을 구현하는 가장 좋은(성능이 중요한 경우) 방법은 무엇입니까?

StackOverflow https://stackoverflow.com/questions/1617894

문제

나는 다음과 같은 옵션을 생각해 냈습니다.

goto 문 사용:

Start:
    goto Data
Data:
    goto Finish
Finish:
    ;

스위치 문을 사용하여:

switch(m_state) {
    case State.Start:
        m_state = State.Data;
        break;
    case State.Data:            
        m_state = State.Finish;
        break;
    case State.Finish:
        break;
}

goto와 스위치를 함께 사용:

switch(m_state) {
    case State.Start:
        goto case State.Data2;
    case State.Data1:
        goto case State.Finish;
    case State.Data2:
        m_state = State.Data1;
        //call to a function outside the state machine
        //that could possibly change the state
        break;
    case State.Finish:
        break;
}

나는 goto 문을 사용하는 첫 번째 옵션을 선호하는데, 그 이유는 이것이 더 빠르고 덜 장황하기 때문입니다.하지만 그것이 최선의 선택인지는 잘 모르겠습니다.성능면에서는 그럴 수도 있지만 가독성에 관해서는 모르겠습니다.그래서 내가 이 질문을 하는 것이다.어떤 옵션을 선호하며 그 이유는 무엇입니까?

도움이 되었습니까?

해결책

goto에 비해 스위치의 장점은 명령 포인터뿐만 아니라 변수에 상태가 있다는 것입니다.

goto 메소드를 사용하면 상태 머신이 다른 모든 것을 제어하는 ​​메인 루프가 되어야 합니다. 왜냐하면 상태를 잃어버리기 때문에 여기서 나갈 수 없기 때문입니다.

스위치 방법을 사용하면 상태 머신이 격리되므로 외부에서 이벤트를 처리하려는 곳 어디든 이동할 수 있습니다.상태 시스템으로 돌아가면 yuu가 중단한 부분부터 계속됩니다.둘 이상의 상태 시스템을 나란히 실행할 수도 있는데, 이는 goto 버전에서는 불가능합니다.

세 번째 대안이 어디로 가고 있는지 잘 모르겠습니다. 주변에 쓸모없는 스위치가 있는 첫 번째 대안처럼 보입니다.

다른 팁

상호 호출/재귀 기능을 선호합니다. 예제를 조정하려면 :

returnvalue Start() {
    return Data();
}

returnvalue Data() {
    return Finish();
}

returnvalue Finish() {
    …
}

이론적으로, 이것 ~할 수 있다 컴파일러 출력이 귀하의 goto 솔루션 (따라서 동일한 속도). 현실적으로, c# compiler /jitter는 아마 그렇게하지 않을 것입니다.. 그러나 솔루션은 훨씬 더 읽기 쉽기 때문에 (음, IMHO), 나는 그것을 goto 솔루션은 매우 신중한 벤치 마크 후이를 입증 한 후 ~이다 실제로 속도 측면에서 열등하거나 스택 오버플로가 발생합니다 (이 간단한 솔루션이 아니라 더 큰 오토마타 가이 문제에 실행됩니다).

그럼에도 불구하고 분명히 고집 goto case 해결책. 왜요? 그렇다면 당신의 모든 지저분하기 때문입니다 goto 파스타는 블록 구조 내부에서 잘 정리되어 있습니다 ( switch 블록) 그리고 당신의 스파게티는 코드의 나머지 부분을 맹글하지 않아 볼로냐를 방지합니다.

결론적으로: 기능 변형은 명확하지만 일반적으로 문제가 발생하기 쉽습니다. 그만큼 goto 해결책은 지저분합니다. 뿐 goto case 반쯤 깨끗하고 효율적인 솔루션을 제공합니다. 성능이 실제로 가장 중요하다면 (그리고 Automaton이 병 목인 경우) 구조화 된 것을 위해 가십시오. goto case 변종.

네 번째 옵션이 있습니다.

반복자를 사용하여 Statemachine을 구현하십시오. 여기에 있습니다 좋은 짧은 기사 방법을 보여줍니다

그래도 몇 가지 단점이 있습니다. 반복자 외부에서 상태를 조작하는 것은 불가능합니다.

나는 그것이 매우 빠른지 확실하지 않습니다. 그러나 항상 테스트를 수행 할 수 있습니다.

상태 머신 전환 로직을 별도의 기능으로 나누고 싶다면 스위치 문을 사용 하여만 수행 할 수 있습니다.

switch(m_state) {
        case State.Start:
                m_state = State.Data;
                break;
        case State.Data:                        
                m_state = ComputeNextState();
                break;
        case State.Finish:
                break;
} 

또한 더 읽기 쉬우 며 스위치 명령문 (GOTO)의 오버 헤드는 드문 상황에서만 성능 차이를 만듭니다.

편집하다:

"goto case"를 사용하여 성능을 약간 향상시킬 수 있습니다.

switch(m_state) {
        case State.Start:
                m_state = State.Data; // Don't forget this line!
                goto case State.Data;
        case State.Data:                        
                m_state = ComputeNextState();
                break;
        case State.Finish:
                break;
} 

그러나 상태 변수를 업데이트하는 것을 잊어 버릴 위험이 있습니다. 나중에 미묘한 버그가 발생할 수 있습니다 ( "M_state"가 설정되었다고 가정했기 때문에) 피하는 것이 좋습니다.

개인적으로 나는 첫 번째 이후로 GOTO를 가진 두 번째 선호를 선호합니다. 이후로 새로운 상태로 이동하려면 불필요한 루프 단계 (예를 들어)가 필요합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top