2017-07-28 43 views
3

我是F#的新手,所以也許這個解決方案對某人來說可能很清楚,但是我找不到它。
想象一下世界大塊的遊戲世界(類似於Minecraft),但是對於更多玩家來說。理論上,像C++,java或C#這樣的語言可以同時修改多個世界塊。兩個或兩個以上的玩家嘗試在不同的塊中放置或移除塊,並且只要每個塊中只有一個動作發生,所有這些動作都可以改變世界的狀態而不會相互影響。序列化只會在一個塊中的多個玩家執行修改時發生。F#同時在多個線程中更新列表

我的F#的理解是我需要序列化對全球一級,這些行動並沒有兩個動作可以在整個世界同一時間發生,因爲更新功能需要actual world stateupdate params(like add/remove blok)並返回new world state
對於該示例,world state包含chunk list

有沒有一種方法可以並行進行世界更新?
world state可以以不同的方式存儲以允許同時更新到多個塊?

+2

在大多數與遊戲相關的代碼中,我會使用'array'而不是'list',除非你特別需要'list'語義(不可變的添加和從前面刪除項目)。如果您在固定大小上進行大量映射,數組通常會更快。 – TheQuickBrownFox

+1

'array'或'list'對於我試圖描述的問題並不重要。如果我正確理解F#,我不能修改'array'或'list'元素,我需要用改變的元素創建一個新的'array'或'list',這不會發生在多個線程上,因爲只有一個新的'array '或'列表'將適用。 – Jakub

+1

實際上,數組是可變的,所以你可以修改元素,但我並不是建議你這樣做。我只是說,既然你在談論一款遊戲,那麼陣列對性能來說是一個很好的默認。 – TheQuickBrownFox

回答

3

聽起來好像你需要確保每個塊有一次一個動作。您可以通過將郵件存儲在郵箱處理器(通常稱爲「代理」)中來保護狀態。您可以從幾個線程向代理髮送幾條消息。他們將一次排隊並處理一個。

有這樣一個詳細的討論在這裏:https://fsharpforfunandprofit.com/posts/concurrency-actor-model/

+1

這就是我想到的,但在'世界對象'。您是否建議將'MailboxProcessor list'存儲在'world state'而不是'chunk list'中?每個'MailboxProcessor'代表'chunk agent',它在運行時需要更新'chunk'並且不需要'list'更新來反映世界編輯操作。我不確定,我需要編寫代碼來確認它,但它看起來像是可以像魅力一樣工作:) – Jakub

+0

@Jakub是的,它可以是代理列表,或者包含代理或可以發佈給代理的功能。 – TheQuickBrownFox

2

首先,我不知道這確實增加任何技術細節,a previous answer,所以你如果你喜歡他們的解決方案,你應該繼續並標記爲答案。然而,我希望這給了一些額外的背景...

問題的根本在於如何一致性的問題,你需要你的世界的狀態是爲了做出有關修改塊的決定。

考慮一個世界,在那裏我有兩個大塊,我們姑且稱之爲A和B.考慮使用情況下我想添加或塊A.刪除塊中的所有重要的問題是:

  • 待辦事項我需要知道塊B中的塊以便驗證,然後執行大塊A中的塊的添加/刪除。

例如,如果我的世界中只有有限的塊數,我可能需要這些信息來驗證我可以添加一個塊,而不會超出我的限制。這裏的關鍵是我的「一致性邊界」是我的整個世界 - 爲了對塊A添加一個新的塊,我需要關於我的世界中每一個元素的一致信息。如果中途做出決定,另一個線程跳轉併爲塊B添加一個塊,這是沒有用的。如果這是一個需求,那麼你沒有選擇 - 即使在C#/ C++的情況下 - 你需要鎖定訪問權限所以只有一個這樣的動作可以在任何時候執行。

從你說出這個問題的方式來看,我懷疑事實並非如此。在這種情況下,我們需要仔細檢查一致性要求是什麼。一個較弱的要求是,如果我將塊添加到塊A,我至少必須獲得有關塊A中塊的數量(和位置)的一致信息。在C#/ C++的情況下,這意味着必須鎖定訪問個人「塊數據」,但不是整個世界。

在F#將(使用this answer建議)建模這個的一個簡單的方法:

open FSharp.Core 

type ChunkMessage = 
    AddBlock 
    | RemoveBlock 

type MyWorld = 
    { 
     Blocks : List<MailboxProcessor<ChunkMessage>> 
    } 

注意MyWorld是可變的,但每個MailboxProcessor封裝狀態只能在通過處理一個消息改變一次。

Blocks的實現並不一定是MailboxProcessor的列表,您可以使用線程安全的對象的線程安全集合,但您可以在其中使用它們,如The Quick Brown Fox導致一個特別好的編程模型。