List F # updates on multiple threads at the same time

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

My understanding of F # is that these actions need to be serialized globally, and at the same time two actions cannot be performed globally, since the update function requires a actual world state

update params(like add/remove blok)

return as well new world state

.
This example world state

contains chunk list

.

Is there a way to do a global update in parallel?
Is it possible to store world state

in different ways to update multiple chunks at the same time?

+3


source to share


2 answers


It sounds like you need to make sure each piece has one action at a time. You can protect pieces of state by storing them inside mailbox processors (often referred to as "agents"). You can send agents to multiple messages from multiple threads. They will be queued and processed in turn.



The following issues are discussed in detail here: https://fsharpforfunandprofit.com/posts/concurrency-actor-model/

+3


source


First, I am not adding any technical details to the previous answer , so if you like their solution you should go ahead and mark it as an answer. However, hopefully this will provide additional context ...

At the heart of your problem is the question of how consistently you need the state of your world to make decisions about changing pieces.

Consider a world where I have two pieces, call them A and B. Consider a use case where I want to add or remove a block from fragment A. The whole important question is:

  • Do I need to know about the blocks in block B to check and then add / remove a block from block A.

For example, if I only have a finite number of blocks in my world, I may well need this information to confirm that I can actually add a block without going over my limit. The key here is that my "consistency boundary" is my whole world - in order to accomplish adding a new block to a chunk. I need consistent information about every type of my world. It's not nice if halfway through my solution when another thread jumps over and adds a block for chunk B. If that's a requirement then you don't have the option - even in the case of C # / C ++ - you need to block access to your world so only one such action can be performed at any time.



From the way you formulate this question, I suspect it is not. In this case, we need to study exactly what exactly you must comply with. A weaker requirement is that if I add blocks to chunk A, I must at least have consistent information about the number (and position) of blocks in chunk A. In the case of C # / C ++, this would mean blocking access to individual "chunk data", but not to the whole world.

A simple way to simulate 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 it MyWorld

is mutable, but each MailboxProcessor

encapsulates state that can only change when processing one message at a time.

The implementation Blocks

doesn't have to be a list MailboxProcessor

, you can use a thread-safe collection of objects for which you've used thread-safe methods, but using them here as suggested by Quick Brown Fox leads to a particularly nice programming model.

+2


source







All Articles