Jakub
Jakub

Reputation: 89

F# update list in multiple threads at same time

I am new to F# so maybe the solution can be clear to someone, but I can not find it.
Imagine a game world of world chunks (similar to Minecraft), but for more players.
In theory language like C++, java, or C# can modify multiple chunks of world at same time. Two or more players try to place or remove block in different chunks and all these actions can change the state of the world without affecting each other as long as no more than one action in each chunk is happening. Serializing will only happen when multiple players in one chunk perform the modification.

My understanding of F# is I need to serialize these actions on global level and no two actions can happen in same time in entire world, because the update function need actual world state update params(like add/remove blok) and return new world state.
For that example the world state contains chunk list.

Is there a way to do world update in parallel?
Can the world state be stored differently to allow update to multiple chunks at same time?

Upvotes: 4

Views: 674

Answers (2)

Lawrence
Lawrence

Reputation: 3297

Firstly, I don't this really adds any technical detail to a previous answer, so you if you like their solution you should go ahead and mark that as the answer. However, I hope this gives some extra context...

Underlying your problem is the question of how consistent do you require the state of your world to be in order to make decisions about modifying chunks.

Consider a world where I have two chunks, let's call them A and B. Consider the use case where I want to add or remove a block from chunk A. The all important question is:

  • Do I need to know about the blocks in chunk B in order to validate, and then perform the addition / removal of a block from chunk A.

For example, if I only have finite number of blocks in my world, I may well need this information to validate that I can actually add a block without going over my limit. The key here is that my "consistency boundary" is my entire world - in order to perform the addition of a new block to chunk A I need consistent information about everythign in my world. It is no good if halfway through my decision making another thread jumps in and adds a block to chunk B. If this is a requirement then you have no option - even in the C#/C++ case - you need to lock down access to your world so only one such action can be performed at anyone time.

From the way you phrase the question, I suspect this is not the case. In which case we need to examine exactly what your consistency requirements are. A weaker requirement is that if I'm adding blocks to chunk A, I at least have to have consistent information about the number (and position) of blocks in chunk A. In the C#/C++ case this would mean having to put locks around accessing to individual "chunk data", but not the whole world.

A simple way of modelling this in F# would be (using the suggestion in this answer):

open FSharp.Core

type ChunkMessage = 
    AddBlock
    | RemoveBlock

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

Note that MyWorld is a mutable, but each MailboxProcessor encapsulates state which can only change through processing one message at a time.

The implementation of Blocks doesn't have to be a list of MailboxProcessor's, you could use a thread-safe collection of objects for which you had thread-safe methods on, but the use of them here as suggested by The Quick Brown Fox leads to a particularly nice programming model.

Upvotes: 2

TheQuickBrownFox
TheQuickBrownFox

Reputation: 10624

It sounds like you need to ensure that each chunk has one action run at a time. You can protect pieces of state by storing them inside mailbox processors (often referred to as just "agents"). You can send agents several messages from several threads. They will be queued and processed one at a time.

There is a detailed discussion of this here: https://fsharpforfunandprofit.com/posts/concurrency-actor-model/

Upvotes: 3

Related Questions