25

私は現在、空き時間に Scala で関数型プログラミングを学んでおり、未熟な初心者の質問があります。

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

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

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

4

8 に答える 8

16

私には、「ティック」ごとに新しいインスタンスの巨大な群れがあるように思えます。

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

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

于 2009-05-16T10:12:02.203 に答える
6

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

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

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

于 2008-10-03T13:48:40.417 に答える
4

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

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

たとえば、Command & Conquer をプレイしているとします。あなたの巨大な戦車は準備完了モードであなたの基地を守っています。対戦相手は軽戦車で近づき、基地を探索します。マンモス戦車が発砲し、相手の戦車に命中してダメージを与えます。

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

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

于 2008-10-03T12:59:40.610 に答える
3

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

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

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

于 2008-10-03T13:41:37.093 に答える
3

ワイヤーレベルでのオブジェクト作成については考えないでください。たとえば、関数型言語用に最適化されたランタイムは、オブジェクトの置き換えに関して「チート」し、既存の構造体の実際のdoミューテーションを実行できる可能性があります。これは、元の構造体を参照するものがなく、新しい構造体が完全に置き換えられることがわかっている場合です。末尾再帰の最適化について考えてみてください。ただし、オブジェクトの状態に適用されます。

于 2008-10-04T13:50:17.980 に答える
3

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

于 2008-10-03T13:27:27.560 に答える
2

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

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

于 2010-02-22T09:47:34.620 に答える
0

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

Eric Lippert は、不変性のトピックに関するいくつかの興味深い投稿を行っており、非常に興味深い読み物です。

于 2008-10-03T11:25:17.143 に答える