F#同时在多个线程中更新列表

时间:2017-07-28 07:46:49

标签: multithreading f#

我是F#的新手所以也许解决方案对某人来说很清楚,但我找不到它 想象一下世界大块的游戏世界(类似于Minecraft),但对于更多的玩家 理论上,像C ++,java或C#这样的语言可以同时修改多个世界的块。两个或更多玩家尝试在不同的块中放置或移除块,并且所有这些动作可以改变世界的状态而不会相互影响,只要每个块中发生的动作不超过一个。序列化仅在一个块中的多个玩家执行修改时发生。

我对F#的理解是我需要在全局范围内序列化这些操作,并且在整个世界中不能同时发生两个操作,因为更新功能需要actual world state update params(like add/remove blok)并返回{{1 }}。
对于该示例,new world state包含world state

有没有办法并行进行世界更新?
chunk list可以以不同方式存储以允许同时更新多个块吗?

2 个答案:

答案 0 :(得分:3)

听起来你需要确保每个块一次运行一个动作。您可以通过将它们存储在邮箱处理器(通常称为"代理商")中来保护状态。您可以从多个线程向代理发送多条消息。它们将一次排队并处理一次。

这里有详细的讨论:https://fsharpforfunandprofit.com/posts/concurrency-actor-model/

答案 1 :(得分: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建议在这里使用它们会产生一个特别好的编程模型。