2012-10-29 23 views
2

在我的大部分Clojure程序......和很多其他Clojure程序我看到,有某種全局變量的一個原子:使用clojure的stm作爲一個全球性的國家被認爲是一種好的做法?

(def *program-state* 
    (atom {:name "Program" 
      :var1 1 
      :var2 "Another value"})) 

這種狀態會在代碼中偶爾被稱爲。

(defn program-name [] 
    (:name @*program-state*)) 

看完這篇文章http://misko.hevery.com/2008/07/24/how-to-write-3v1l-untestable-code/讓我重新思考全局狀態,但不知何故,即使我完全文章同意,我認爲它好使用哈希映射中的原子,因爲它提供了一個通用的接口用於操縱全局狀態數據(類似於使用不同的數據庫來存儲您的數據)。

我想就此問題想一些其他想法。

+0

不,這不是一個好習慣。避免它像瘟疫一樣。如果你必須這樣做,那麼儘量減少接觸或知道的代碼量。全球狀態是模塊化和組合性的敵人。它將代碼耦合在一起,難以重構或修復。 –

+1

如果您想通過repl與程序進行交互,您需要擁有一些全局狀態。當然,你實際上並不需要告訴你的主程序狀態是在全球範圍內暴露出來的,最好是編程好像它不是。 – Cubic

回答

2

這種事情可以,但它也經常是一種設計氣味,所以我會小心處理。

事情要考慮:

  • 一致性 - 可以將代碼中的一個部分改變程序的名字嗎?如果是的話,program-name函數從其他線程的角度來看將表現不一致。不好!
  • 可測性 - 這很容易測試嗎?可以將正在更改程序名稱的測試套件的一部分安全地與另一個正在讀取名稱的測試同時運行?
  • 多個實例 - 你會有兩個不同的應用程序部分,希望同時使用不同的程序名嗎?如果是這樣,這是一個強烈的暗示,你的可變狀態不應該是全球性的。

替代考慮:

  • 使用REF代替原子的,可以至少確保交易
  • 內可變狀態的一致性使用結合可以限制可變性的按線程計算。這解決了大多數併發問題,並且在使用全局變量(如一組線程本地配置參數)時會很有幫助。
  • 使用不變的全局狀態無論你在哪裏。它真的需要可變嗎?
+0

+1多個實例評論:)不計劃需要兩個全局狀態創建匍匐問題... –

2

我認爲有一個單一的全局狀態偶爾以交換方式更新是好的。當你開始有兩個需要更新的全局狀態並且線程開始使用它們進行通信時,我開始擔心。

  • 維持目前全球用戶的計數是好的:
    • 任何線程可以在任何時候不傷害另一個
    • 如果它在你的線程沒有爆炸改變了INC或DEC這一點。
  • 維護日誌目錄是值得商榷的:
    • 當它改變時將所有的線程停止寫入舊的?
    • 如果兩個線程發生變化,它們會收斂。
  • 以此爲消息隊列是更加可疑:
+0

謝謝!你對這篇文章有什麼想法:http://gen5.info/q/2008/07/25/the-multiton-design-pattern/ – zcaudate

+0

@zcaudate:這篇文章是一篇典型的OO文章,關於「另一種設計模式」 ...我會建議..不要這樣做:) – Ankur

+0

然後你將如何實現一個消息隊列?我不完全確定我現在是否需要這個,但是我相信對於我目前的項目,我遲早會遇到一種需要消息隊列的情況(即從IO線程獲取密鑰按下一個線程處理邏輯)。 – Cubic

1

,我認爲它是好的能有這樣的全局狀態(在許多情況下,它是必需的),但我會小心的是我的應用程序的核心邏輯具有以狀態爲參數並返回更新狀態而不是直接訪問全局狀態的功能。基本上我寧願從幾個功能集中控制對全局狀態的訪問,而我的程序中的其他任何部分都應該使用這些方法訪問狀態,因爲這樣我就可以抽象出狀態實現,即最初可以啓動與內存原子,然後可能會移動到一些持久性存儲。

相關問題