2017-07-28 17 views
3

私はF#を初めて使っています。だから、おそらく解決策は誰かには分かりますが、見つけられません。
ワールドチャンク(Minecraftに似ています)のゲーム世界を想像してください。
C++、java、C#などの理論言語では、同時に複数のチャンクを変更できます。 2人以上のプレイヤーがブロックを別々のチャンクに配置または削除しようとします。これらのアクションは、各チャンク内に複数のアクションが発生していない限り、互いに影響を与えずに世界の状態を変えることができます。シリアライズは、1つのチャンク内の複数のプレーヤーが変更を実行する場合にのみ発生します。F#複数のスレッドで同時にリストを更新する

のF#の私の理解では、更新機能がactual world stateupdate params(like add/remove blok)を必要とnew world stateを返すので、私は、全世界で同時期に発生する可能性がグローバルレベルでのこれらのアクションなし2つのアクションをシリアル化する必要があります。
world stateにはchunk listが含まれています。

世界の更新を並行して行う方法はありますか?
world stateを別々に保存して、複数のチャンクに同時に更新することはできますか?

+2

ほとんどのゲーム関連のコードでは、 'list'セマンティクスが特に必要な場合を除いて' list'の代わりに 'array'を使用します(前の項目の不変な追加と削除)。配列は、固定サイズ以上のマッピングをしている場合は通常より高速です。 – TheQuickBrownFox

+1

'array'または' list'は、私が記述しようとする問題のために重要ではありません。私がF#を正しく理解していれば、 'array'または' list'要素を変更することはできません。変更された要素で 'array'または' list'を作成する必要があります。 'または' lists'が適用されます。 – Jakub

+1

実際には配列は変更可能なので、要素を変更することはできますが、私はあなたにそれを提案していませんでした。私はあなたがゲームについて話しているので、配列はパフォーマンスの良いデフォルトです。 – TheQuickBrownFox

答えて

3

各チャンクに一度に1つのアクションが実行されるようにする必要があるように思えます。状態をメールボックスプロセッサー(しばしば「エージェント」と呼ばれる)内に格納することで、状態を保護することができます。エージェントには、複数のスレッドから複数のメッセージを送信できます。それらはキューに入れられ、一度に1つずつ処理されます。

本の詳細な説明はここにあります:まずhttps://fsharpforfunandprofit.com/posts/concurrency-actor-model/

+1

それは私が考えているのですが、「世界の物体」です。 'chunk list'ではなく' world state'に 'MailboxProcessor list'を保存することをお勧めしますか?各 'MailboxProcessor'は、' chunk'を更新する 'chunk agent'を表し、実行時にワールド編集アクションを反映するための' list'アップデートは必要ありません。私はそれを確認するためにそのコードを書く必要がありますが、それは魅力のように動作するように見える:) – Jakub

+0

@Jakubはい、まさにそれはエージェントのリスト、またはエージェントまたはエージェントに通知できる機能が含まれています。 – TheQuickBrownFox

2

、私はあなたが彼らのソリューションを好きならあなたは答えとしてそれを先に行くとマークする必要がありますので、これは本当に、a previous answerへの技術的な詳細を追加しません。しかし、私はこれは、いくつかの余分なコンテキストを与える願っています...

はあなたの問題を根底には、あなたがチャンクを変更に関する決定を行うためにあるようにあなたの世界の状態を必要としない方法を一貫性の問題です。

のは、Aそれらを呼び出すとBは私がすべての重要な質問は、チャンクAからブロックを追加または削除するユースケースを考えてみましょう、私は2つのチャンクを持って世界を考えてみましょう:

  • ドゥ検証するためにチャンクB内のブロックについて知ってから、チャンクAからブロックの追加/削除を実行する必要があります。

たとえば、自分の世界に有限個のブロックしかない場合、私は実際に私の限界を超えないでブロックを追加することができることを検証するためにこの情報が必要になるかもしれません。ここで重要なことは、私の "一貫性の境界"が私の世界全体であることです。新しいブロックをチャンクAに追加するためには、私の世界のすべてのことについて一貫した情報が必要です。それを途中で私の決定を介して、他のスレッドを作成するにジャンプし場合チャンクB. にブロックを追加した場合、これは必要条件では良いではありません、あなたは何のオプションがありません - でもC#/ C++の場合を - あなたはへのアクセスをロックダウンする必要がありますあなたの世界は誰にでもそのような行動を1回だけ実行できます。

フレーズ質問を途中から、私はこれが当てはまらないと思います。この場合、整合性要件が何であるかを正確に調べる必要があります。弱い要件は、私はチャンクAにブロックを追加している場合、私は少なくともこれは周りにロックを置くことを有することを意味だろうC#の/ C++の場合には、チャンクAのブロック数(および位置)に関する一貫した情報を持たなければならないということです個々の「チャンクデータ」にアクセスするが、全世界にはアクセスしない。

F#でこれをモデル化する簡単な方法は、(this answerに提案を使用して)次のようになります

open FSharp.Core 

type ChunkMessage = 
    AddBlock 
    | RemoveBlock 

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

MyWorldが可変であるが、各MailboxProcessorのみで処理つのメッセージを介して変更することができる状態をカプセル化すること時間。

Blocksの実装はMailboxProcessorのリストである必要はありませんが、スレッドセーフな方法を使用したオブジェクトのスレッドセーフなコレクションを使用できますが、 The Quick Brown Foxは特に素晴らしいプログラミングモデルにつながります。

関連する問題