質問

現在、Scalaで暇なときに関数型プログラミングを学んでいますが、初心者の質問がありません。

Haarウェーブレット変換の計算のようなことをするとき、つまり、オブジェクトによって表されるデータ自体が変わらないとき、不変オブジェクトを持つ優雅さを見ることができます。

しかし、不変性を実証する例として、誰かが小さなゲームをしているブログを見ました。クリーチャーオブジェクトがダメージを受けた場合、その状態は変化しませんでした。新しいヒットポイントと新しい「Xに向かうアグロ」を持つ新しいクリーチャーオブジェクトを返しました。フラグ。しかし、MMORPGのようなものを設計する場合、World of Warcraftは言います。戦場にいる100人のプレイヤー...数千の攻撃と、さまざまな方法で影響を与えるバフ/デバフスペルエフェクト。完全に不変のオブジェクトでシステムを設計することはまだ可能ですか?私には、それぞれが「カチカチ」音を立てる新しいインスタンスの巨大な群れがあるように思えます。そして、現在有効なオブジェクトのインスタンスを取得するには、すべてのクライアントが常に何らかの中心的な「ゲームワールド」を通過する必要があります。オブジェクト、または?

これに対して関数型プログラミングはスケールしますか、またはこれは「最高の仕事に最適なツールで、おそらくここでは不変ではない」場合ですか?

役に立ちましたか?

解決

  

私には、それぞれが「カチカチ」音を立てる新しいインスタンスの巨大な群れがあるように思えます。

確かにそうです。 Haskellアプリケーションを使用して、市場データフィード(6時間の取引で関心のあるデータについて約500万メッセージ)を読み取り、「現在の状態」を維持します。機器の最新のビッドとオファーの価格と数量、モデルが市場にどの程度適合するかなど、さまざまなことに対して。プロファイリングモードとウォッチで記録されたフィードに対してこのプログラムの実行をシミュレートするのはかなり恐ろしいことです実行の最初の500秒で288 TBに近いメモリ(またはマシンのRAMのサイズの50,000倍に近い)を割り当ててGCを実行します。 (プロファイリングによりアプリケーションの速度が低下するだけでなく、すべてが1つのコアで実行されるため、プロファイリングなしではこの数値はかなり高くなります。)

ただし、純粋な言語の実装のガベージコレクターは、このような動作に最適化されています。私はアプリケーションの全体的な速度に非常に満足しており、市場フィードから毎秒数百のメッセージを解析し、かなり広範な計算を行ってモデルを構築し、それを使用しなければならないという点で、かなり厳しいと思いますできるだけ早く取引所に行く注文を生成するモデル。

他のヒント

通常、関数型プログラミングでは、C ++スタイルのコンストラクターはありません。そして、概念的には常にオブジェクトを作成しているとしても、プログラムの動作に影響を与えないため、コンパイラが新しいオブジェクトを割り当てるためにコードを作成する必要があるわけではありません。データは不変であるため、コンパイラは、指定した値と関数に渡された値を確認できます。

その後、コンパイラは、必要なときに特定のオブジェクトのフィールドを計算するだけの非常にタイトなコンパイル済みコードを 作成できます。これがどの程度うまく機能するかは、使用するコンパイラの品質に依存します。ただし、クリーンな関数型プログラミングコードは、同様のプログラムのCコンパイラが想定するよりもかなり多くのコードをコンパイラに伝えます。したがって、優れたコンパイラは、予想よりも優れたコードを生成する可能性があります。

したがって、少なくとも理論的には、心配する理由はありません。関数型プログラミングの実装は、オブジェクト指向のヒープ割り当て実装と同様に拡張できます。実際には、使用している言語実装の品質を理解する必要があります。

MMORPGは、不変の例です既にです。ゲームはサーバーとゲーマーのシステム全体に分散しているため、中央の「ゲームワールド」は絶対にありません。オブジェクト。したがって、有線で送信されるオブジェクトは不変です—受信者によって変更されないためです。代わりに、新しいオブジェクトまたはメッセージがあれば、応答として送信されます。

分散ゲームを書いたことがないので、それらがどのように実装されているか正確にはわかりませんが、オブジェクトの更新はローカルで計算されるか、ワイヤー経由で差分として送信されると思います。

たとえば、コマンド&をプレイしています。征服する。マンモスタンクは、基地を守る準備モードで座っています。対戦相手は軽戦車を使って基地を探索します。マンモスの戦車が敵の戦車を撃って攻撃し、ダメージを与えます。

このゲームは非常にシンプルなので、可能な限りローカルで多くの計算が行われると思います。 2人のプレイヤーのコンピューターは、最初はゲームの状態に関して同期していると仮定します。次に、相手がクリックして軽戦車を基地に移動します。メッセージ(不変)がネットワーク経由で送信されます。戦車を動かすアルゴリズムは(おそらく)決定論的であるため、Command&のコピーは征服すると、対戦相手の戦車が画面上で移動し、ゲームの状態が更新されます(不変または可変になります)。軽戦車がマンモス戦車の射程内に入ると、戦車が発砲します。サーバーでランダムな値が生成され(この場合、1台のコンピューターがサーバーとして任意に選択されます)、ショットが相手にヒットするかどうかが決定されます。戦車がヒットし、対戦相手の戦車を更新する必要があると仮定します。差分のみを#&8212;戦車の新しい装甲レベルが22%に低下したという事実— 2人のプレイヤーのゲームを同期するために、有線で送信されます。このメッセージは不変です。

戦車を表すいずれかのプレイヤーのコンピューター上のオブジェクトが可変であるか不変であるかは関係ありません。どちらの方法でも実装できます。各プレイヤーが他のゲーマーのゲームの状態を直接変更することはありません。

不変性に関する注意点の1つは、(正しく実装されていれば)オブジェクトの作成が比較的軽量になることです。フィールドが不変の場合、インスタンス間で共有できます。

関数型プログラムを設計する際には、あなたが述べているように、不変オブジェクトにいくらかのオーバーヘッドがあることを考慮することが重要です。また、MMORPGプログラム内のオブジェクトを不変にすることにより、本質的にスケーラブルになることを覚えておくことが重要です。そのため、機器への初期投資は高くなる可能性がありますが、状況が拡大するにつれて、プレイヤーベースに合わせてスケールできるようになります。

考慮すべきもう1つの重要なことは、現時点で最も高速なマシンにはCPUあたり6コアがあることです。それぞれ6コアのデュアルCPUマシンを検討してください。これらの12のコアの1つはガベージコレクションを実行できるため、多くのオブジェクトを破棄することによるオーバーヘッドは、アプリケーションが他の11のコアに簡単に拡張できることで相殺できます。

また、すべてのオブジェクト(およびそのサブオブジェクト)をコピーで完全に再構築する必要があるわけではないことも覚えておいてください。オブジェクトが「コピー」された場合、変更されなかった参照タイプは、単一の参照割り当てのみを取ります。

ワイヤーレベルでのオブジェクト作成は考えないでください。たとえば、関数型言語向けに最適化されたランタイムは、おそらく「チート」できるでしょう。オブジェクトを置き換え、既存の構造体を実際に変更する場合、元の構造体を参照するものが何もないことがわかっていて、新しい構造体がそれを完全に置き換えます。末尾再帰最適化を考えてください。ただし、オブジェクトの状態に適用されます。

今日、この投稿で提起した質問を正確に扱ったブログを見つけました。

http://prog21.dadgum.com/23.html

プログラミングのほとんどすべてのツールと同様に、不変オブジェクトは強力ですが、間違った状況では危険です。ゲームの例はあまり良いものではないか、少なくとも非常に不自然だと思います。

Eric Lippertのトピックに関する興味深い投稿不変であり、非常に興味深い読み物です。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top