2017-07-28 40 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导致一个特别好的编程模型。