簡體   English   中英

在C#中實現狀態機的最佳方法(性能何時重要)?

[英]What's the best(when performance matters) way to implement a state machine in C#?

我想出了以下選項:

使用goto語句:

Start:
    goto Data
Data:
    goto Finish
Finish:
    ;

使用switch語句:

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一起:

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語句的第一個選項,因為它更快,更簡潔。 但我不確定它是不是最好的選擇。 表現明智,但是當談到可讀性我不知道。 這就是我問這個問題的原因。 您更喜歡哪個選項?為什么?

我更喜歡相互調用/遞歸函數。 要適應你的例子:

returnvalue Start() {
    return Data();
}

returnvalue Data() {
    return Finish();
}

returnvalue Finish() {
    …
}

從理論上講,這可以完全內聯,因此編譯器輸出等同於你的goto解決方案(因此速度相同)。 實際上, C#編譯器/ JITter可能不會這樣做 但是,由於該解決方案是大大更具可讀性(好吧,恕我直言),我只會用替換它goto一個非常仔細的標桿證明它在速度方面的確遜色,或出現堆棧溢出(在此簡單的解決方案之后,解決方案但是更大的自動機會遇到這個問題)。

即便如此,我肯定會堅持使用goto case解決方案。 為什么? 因為那么你的整個凌亂goto面食是公包封的嵌段結構(內部switch塊)和您的面條不會裂傷的代碼的其余部分,從而防止波倫亞。

總之 :功能變體很清楚,但通常容易出問題。 goto解決方案很麻煩。 只有goto case提供了一個干凈,高效的解決方案。 如果性能確實是最重要的(並且自動機是瓶頸),那么請選擇結構化的goto case變體。

切換goto的優點是你在變量中有狀態,而不僅僅是在指令指針中。

使用goto方法,狀態機必須是控制其他所有內容的主循環,因為你不會因為丟失狀態而退出它。

使用切換方法,狀態機是隔離的,您可以到任何想要處理外部事件的地方。 當你返回狀態機時,它會繼續在yuu停止的地方繼續。 您甚至可以並排運行多個狀態機,這是goto版本無法實現的。

我不確定你在第三種方案中走向何方,它看起來就像是第一種無用的開關。

如果您希望將狀態機轉換邏輯分解為單獨的函數,則只能使用switch語句執行此操作。

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

它也更具可讀性,並且switch語句(與Goto相比)的開銷只會在極少數情況下產生性能差異。

編輯:

您可以使用“轉到大小寫”來提高性能:

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 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM