2015-08-20 57 views
18

我對在應用程序中使用不可變數據的好處有一個很好的想法,我對在簡單的同步編程環境中使用這些不可變結構的想法感到滿意。異步系統中的不可變數據

有堆棧溢出的某處一個很好的例子,通過一系列遞歸調用,像這樣的傳遞狀態一起描述了一個遊戲管理狀態:

function update(state) { 
    sleep(100) 

    return update({ 
    ticks: state.ticks + 1, 
    player: player 
    }) 
} 

我們可以做一些隨心所欲,副作用對函數體內的自由工作產生影響,那麼我們將返回一個新狀態,而不是改變舊狀態。

這似乎很容易翻譯成一個簡單的異步模型,說Javascript。

function update(state) { 
    const newState = { 
    player, 
    ticks: state.ticks + 1 
    }; 

    setTimeout(update.bind(this, newState), 100); 
} 

但是,只要我們有異步事件的詳細來源,這似乎成爲了很多難以管理,以保持狀態不變和功能純粹。

如果我們在示例中添加一個click事件,我們最終得到的代碼如下所示。

window.addEventListener('click', function() { 
    // I have no idea what the state is 
    // because only our update loop knows about it 
}); 

現在很明顯,我不想在突變這種方法的狀態,但我需要以創建一個新的狀態,這樣的訪問狀態。

window.addEventListener('click', function() { 
    const state = getState(); 

    createState({ 
    player, 
    clicks: clicks + 1 
    }); 
}); 

但是這似乎需要某種可變狀態管理器?

另外,我想我可以在點擊事件添加到一個動作隊列中的更新循環內進行處理,這樣的:

window.addEventListener('click', function() { 
    createAction('click', e); 
}); 

function update(state, actions) { 
    const newState = { 
    player, 
    ticks: state.ticks + 1, 
    clicks: state.clicks + actions.clicks.length 
    }; 

    setTimeout(update.bind(this, newState, []), 100); 
} 

同樣,這並不感到特別的功能,並在依賴在某種程度上至少有一些可變狀態。這些可能來自於主要從事可變狀態和命令式面向對象編程的人的天真做法。

當存在多個異步事件源並且我們希望所有東西都是不變的時,系統的設計是什麼樣的?或者至少,在這樣的系統中控制可變性的好方法是什麼?

+6

您正在尋找的功能反應式編程(FRP)。 – Bergi

+3

這個隊列實際上聽起來像一個合理的方式(只是不要忘記在'update'中使用它之後清除它)。但事實上,你總是需要你的程序的一些小部分是可變的,因爲像點擊這樣的事件*必須*有副作用(或者根本沒有做任何事情)。 Immutabiltity並不是說你的程序從不做任何事情,而是關於你正在做的事情的合理建模。 – Bergi

+1

同意@Bergi。按照定義,事件是有狀態的;根據定義,輸入是可變的。你可以做的最好的事情是儘可能地將可變狀態從不可變狀態中分離出來。隊列實際上運行良好(特別是從遊戲的角度來看;我自己也使用過),所以對於你的情況,隊列可以是可變的 - 你可以繼續添加事件 - 直到下一次更新運行。此時,您需要創建一個不可變的隊列副本。之後,你可以堅持不變的構造。 –

回答

4

您可能會喜歡看一下Redux。 Redux採取了類似的方法:

  • 它將整個應用程序狀態建模爲單個不可變對象。
  • 用戶操作本質上是分派給store進行任意處理的消息。
  • 操作由處理器處理函數的形式爲f(previousState, action) => newState。這是比原始版本更實用的方法。
  • store運行reducer並維護一個不可變的應用程序狀態。

你說得對,這不是完全不可改變的,因爲商店本身對當前狀態有一個可變的引用。但正如其他人所指出的,對於大多數不可變數據的概念來說,這似乎不是一個問題。

除了UI操作之外,還可能有一個在循環中觸發的tick操作 - 它只是另一個輸入事件,由同一組減速器處理。

0

使用Object.freeze,可以使對象不變:

var o = {foo: "bar"}; 
Object.freeze(o); 
o.abc = "xyz"; 
console.log(o); 

將產生{foo: "bar"}。請注意,嘗試在凍結變量上設置新屬性將失敗。

在這種情況下,創建新狀態對象後,在調用更新例程或觸發事件之前將其凍結,以防止進一步修改。

+0

我想你可能誤解了這個問題。我完全瞭解如何製作和管理不可變數據。問題是關於跟蹤多個異步事件之間的應用程序狀態。 –

1

在試圖直接回答你的問題:?

「什麼是設計一個系統看,當有多個異步事件源一樣,我們希望一切是不可變的,或者至少,什麼是好的在這樣的系統中控制可變性的模式?「

在unix世界中,正確的解決方案模式自從系統5以來一直是異步FIFO消息隊列(AMQ),而理論上存在競爭條件和狀態不確定性可能發生的條件實踐它幾乎從來沒有。事實上,對AMQs可靠性的早期研究確定,這些錯誤並不是由於傳輸滯後,而是由於與同步中斷請求的衝突,因爲早期的AMQ本質上只是在內核空間中實現的管道。現代解決方案,實際上是Scala解決方案,是在共享受保護的內存中實現AMQ,從而消除緩慢且潛在危險的內核調用。因爲事實證明,如果你的總消息帶寬小於總信道容量,並且你的傳輸距離小於一秒的距離 - 電阻/切換,你的失敗概率在宇宙上很低(例如大約爲10^-24)。有各種各樣的理論原因,但是如果沒有對量子物理學和信息理論的深入研究,這裏就不能真正精確地解決這個問題,但是還沒有找到證明確實如此的數學證明,這都是估計和實踐。但是,對於可靠的異步通信,unix的每種風格都依賴於30多年的這些估計。

如果您想知道如何引入中斷行爲,那麼設計模式可以是直接或次優先級排隊,增加優先級或排序級別會爲消息清單增加小的開銷,並且可以如何組成同步和異步調用。

用多個可變指令保存不可變啓動狀態的設計模式類似於狀態保留模式,可以使用歷史或差異隊列。歷史隊列存儲原始狀態和狀態更改數組,如撤消歷史記錄。差異隊列保存初始狀態和所有變化的總和(稍微小一些,但速度較快,但這些日子並不算大)。最後,如果您確實需要處理大量或分組消息,這些消息需要經過大量距離複雜的網絡或重複進出內核,則設計模式是添加回調函數的起始地址和時間戳以及糾正處理很少,這就是爲什麼TCP/IP,SMQ,Netbios等都將協議包含在協議中的原因,所以如果您需要這樣做,請修改優先級/排序隊列以便識別數據包。

我意識到這是對一個巨大主題的草率處理,這就是爲什麼我很高興迴應,如果有任何進一步的問題或需要澄清的問題。

我希望我能回答你的問題,而且不會偏離你提出的問題。 :)

後期編輯:

下面是如何以及爲何使用這些種類型的隊列設計的分佈式併發應用一些很好的例子,它們用於大多數FRP分佈式設計方案的心臟:

https://docs.oracle.com/cd/E19798-01/821-1841/bncfh/index.html

https://blog.codepath.com/2013/01/06/asynchronous-processing-in-web-applications-part-2-developers-need-to-understand-message-queues/

http://www.enterpriseintegrationpatterns.com/patterns/messaging/ComposedMessagingMSMQ.html

http://soapatterns.org/design_patterns/asynchronous_queuing

http://www.rossbencina.com/code/programming-with-lightweight-asynchronous-messages-some-basic-patterns

http://www.asp.net/aspnet/overview/developing-apps-with-windows-azure/building-real-world-cloud-apps-with-windows-azure/queue-centric-work-pattern

http://spin.atomicobject.com/2014/08/18/asynchronous-ios-reactivecocoa/

http://fsharpforfunandprofit.com/posts/concurrency-reactive/

和馬丁·奧德斯基視頻......

https://www.typesafe.com/resources/video/martin-odersky---typesafe-reactive-platform

:)