2009-08-14 3 views
5

編集:gen_serverモジュールをどのようにパラメータ化しますか?

私はErlangプログラムを構築するための汎用的な方法としてパラメータを使用するつもりはありません - 私はまだ伝統的な設計原則を学んでいます。私はOOPをエミュレートしようとも考えていません。私のここでの唯一のポイントは、gen_server呼び出しをサーバーインスタンス間で一貫性を持たせることです。これは壊れた抽象を私に固定するような感じです。言語やOTPがgen_serverインスタンスのAPIを使用するのに便利な世界を想像することができます。それは私が住みたい世界です。

私の主な目的が可能であることを示すためにZedに感謝します。


gen_serversでパラメータ化されたモジュールを使用する方法を理解できますか?次の例では、test_childが1つのパラメータを持つgen_serverであると仮定します。私はそれを起動しようとすると、私が得るすべては次のとおりです。最終的に

42> {test_child, "hello"}:start_link(). 
** exception exit: undef 
    in function test_child:init/1 
     called as test_child:init([]) 
    in call from gen_server:init_it/6 
    in call from proc_lib:init_p_do_apply/3 

、私はgen_serverの複数の名前付きインスタンスを使用する方法を把握しようとしています。私が言うことができる限り、すぐにそれをやってみるとすぐに、きれいなAPIを使用することはできず、gen_server:callとgen_server:castを使用してインスタンスにメッセージを投げなければなりません。インスタンスに名前を伝えることができれば、この問題は緩和されます。

+0

それぞれ異なる名前の同じコールバックモジュールを使用して、複数のgen_serversを作成しますか?同じ名前の複数のgen_servers? – Jacob

+0

同じコールバックモジュールを使用する複数のgen_servers。 start_linkに名前を渡して、別の「インスタンス」を登録することができます。 1つのインスタンスがある場合は、モジュールと同じ名前を付けるのが一般的で、公開APIは次のように動作します。 some_module:some_function() ...これは単なる利便性のようです。 gen_serverを別の名前で登録すると、それはもう動作しません。 私は次のようなものにしたいと思います。 1> Mod:some_function()。 2> Mod1:some_function()。 ...各変数はgen_serverモジュールの異なるインスタンスを参照します – mwt

+0

あるいは、なぜこれに気を付けるべきではないかを知りたいと思います。私が見たすべてのgen_serverイントロでは、単にgen_serverキャスト/コールを使用するのではなく、APIを設定しています。Erlangの新機能であるので、私は簡単に多くのプロセスをクローンできると思っていましたが、gen_serversの名前を変更するとすぐにAPI機能が停止するのは驚きです。 – mwt

答えて

-4
-module(zed, [Name]). 
-behavior(gen_server). 

-export([start_link/0, init/1, handle_cast/2]). 
-export([increment/0]). 

increment() -> 
    gen_server:cast(Name, increment). 

start_link() -> 
    gen_server:start_link({local, Name}, {?MODULE, Name}, [], []). 

init([]) -> 
    {ok, 0}. 

handle_cast(increment, Counter) -> 
    NewCounter = Counter + 1, 
    io:format("~p~n", [NewCounter]), 
    {noreply, NewCounter}. 

このモジュールは私のために正常に動作している:

Eshell V5.7.2 (abort with ^G) 
1> S1 = zed:new(s1). 
{zed,s1} 
2> S1:start_link(). 
{ok,<0.36.0>} 
3> S1:increment(). 
1 
ok 
4> S1:increment(). 
2 
ok 
+0

ありがとうございます。これを私のプロジェクトに追加して、そのメリットがこのスレッドでもたらされた異論よりも重要かどうかを確認します。 – mwt

+1

私はこの答えに否定的な票は、物事をクリアする必要がありますね:) – gleber

+0

私はすでにあなたとarchaelusがパラメータ化されたモジュールに賛成ではないと思ったが、カウントがありがとう:) – Zed

3

私はあなたがこの機能をこのように使うべきではないと思います。あなたはあなたのgen_serversにオブジェクト指向のようなインターフェイスの後に行くように見えます。この目的のためにローカルに登録された名前を使用しています - 多くの共有状態をプログラムに追加します。これはです。悪いことです。重要なサーバーと中心サーバーだけをregister BIFに登録する必要があります。他のすべてのサーバーは無名にして、マネージャーの上にマネージャー(これはおそらく何らかの名前で登録する必要があります)によって管理されます。

+0

"それらの上にあるマネージャ"と機能面で組み込みのプロセスレジストリの違いは何ですか? – Zed

+1

違いは、マネージャは特別なプロセスであり、これは一度に1つのことを行います。組み込みプロセスレジストリは中央サーバの汎用レジストリですが、グローバルに(ノード上で)アクセスする必要があります。名前の衝突の可能性は、プロセスレジストリを使用する場合にはるかに高くなります。さらに、AFAIKプロセスレジストリは、多数のアイテムを格納するためのものではありません。登録されたプロセスの数が少ないためです。 – gleber

+0

私はあなたの意見に同意し、OO世界の依存性注入フレームワークとの類似点を見ています。グローバル静的ファクトリメソッドを持つよりも、依存性注入が使用されます。隔離とモジュール性が向上し、テストが容易になります。重要な中央サーバであっても、ハードコードされた原子名で参照されるべきではなく、それらの原子がパラメータとしてジェネサーバーに渡される必要があります。パラメータ化されたモジュールは、私が概説した問題がなければ、一度アプローチするでしょう。これが私がいつも明白な普通の明示的な状態を常に使う理由です。ハードコーディング名は監督者の行動のためのものです。 – Christian

10

この回答には2つの部分があります。第一に、Erlangにかなり熟練するまで、paramatizedモジュールを使用したくないということです。彼らがあなたに与えるのは、引数を渡す別の方法です。

-module(test_module, [Param1]). 

some_method() -> Param1. 

は、前者が全くずっとあなたを購入していません

-module(test_non_paramatized_module). 

some_method(Param1) -> Param1. 

と同等であり、非常に少ない既存のErlangのコードは、そのスタイルを使用しています。

start_link関数にname引数(異なる名前で登録された同じgen_serverをいくつも作成していると仮定します)を渡す方が通常です。

start_link(Name) -> gen_server:start_link({local, Name}, ?MODULE, [Name], []). 

回答への第2の部分は、gen_serverはparamatizedモジュールと互換性があることである。

-module(some_module, [Param1, Param2]). 

start_link() -> 
    PModule = ?MODULE:new(Param1, Param2), 
    gen_server:start_link(PModule, [], []). 
Param1

Param2は、すべてのgen_serverコールバック関数で利用できるようになります。

start_linkがparamatizedモジュールに属しているようゼッドは、言及として、あなたはそれを呼び出すために、次の手順を実行する必要があります:

Instance = some_module:new(Param1, Param2), 
Instance:start_link(). 

私は、これは特に醜いスタイルであることがわかりました - 呼び出すコードsome_module:new/nは、モジュールパラメータの数と順序を知っていなければなりません。 some_module:new/nを呼び出すコードもsome_moduleには存在しません。これにより、モジュールのパラメータの数や順序が変更されると、ホットアップグレードがより困難になります。 some_moduleコードをアップグレードする方法が見つかったとしても、2つのモジュール(some_moduleとそのインターフェイス/コンストラクタモジュール)の代わりに2つのモジュールのロードを調整する必要があります。マイナーノートでは、このスタイルにより、some_module:start_link用のコードベースをgrepするのがやや難しくなります。


gen_serversにパラメータを渡すために推奨される方法は、gen_server:start_link/3,4関数の引数を経由して、明示的であり、あなたが?MODULE:init/1 callackから復帰状態値に格納します。このスタイルを使用して

-module(good_style). 

-record(state, {param1, param2}). 

start_link(Param1, Param2) -> 
    gen_server:start_link(?MODULE, [Param1, Param2], []). 

init([Param1, Param2]) -> 
    {ok, #state{param1=Param1,param2=Param2}}. 

は、あなたがまだ完全にparamatizedモジュール(新しい、まだ実験的な機能)をサポートしていないOTPのさまざまな部分でキャッチされないことを意味します。また、gen_serverインスタンスの実行中に状態値を変更できますが、モジュールパラメータでは変更できません。

このスタイルでは、コード変更メカニズムによるホットアップグレードもサポートしています。 code_change/3関数が呼び出されると、新しい状態値を返すことができます。新しいparamatizedモジュールインスタンスをgen_serverコードに返す対応する方法はありません。

+0

私はあなたの2番目の部分のポイントが表示されません。パラメータ化されたモジュールには「静的」な関数はありません(私もそれを逃してしまいます)。 some_module:new/2を前に呼び出すことなく、start_link()を呼び出すことはできません。 – Zed

+0

もちろん、新しいパラメータ化されたsome_moduleを返すstart_link()を持っているsome_module_factoryのような別個のモジュールを持つことができますが、私たちはあまりにも複雑なコーディングをしています... – Zed

+2

私はあなたがgen_server:call/2を介してparam化されていないgen_serverと通信しています。これにより、gen_serverのアップグレードの問題を避けることができ、サーバー参照を別の方法で(関数パラメーターではなくparamatizedモジュールとして)渡すことを意味します。あなたはまだコーディネーティング2モジュールのアップグレードの問題が残っていますが、これは良いスタイルとしてはお勧めできません。 – archaelus

10

私はちょうど2つの事を言いたい:

  • archaelusはそれを正しく説明しています。彼が言うように、最終的な方法は、それを行うための推奨された方法であり、あなたが望むことを実行するということです。

  • 決して、NEVER、NEVER NEVERあなたがしようとしていたフォームを使用!それはあなたが意図したことを決して意味しなかった昔から残されたものであり、今では強く非難されています。

+0

@mwt、Robertの点を考慮してください。彼はErlangのクリエイターの一人であり、Erlang-newbieが耳を傾けるべきだと確信しています! – gleber

+0

まあ、私に知らせてくれてありがとう。私は彼が作るコメントに特に注意を払う。:) 最初の点については、コメントの順序は物事を混乱させる可能性があります。私は彼がarchaelusを指しているかどうかは今のところ最後か2番目かを知ることができませんが、2番目から最後まで考えています。もしそうなら、これはzedの例に似ています。 ポイント2については、とにかくそのスタイルを実際に使用するつもりはありませんでした。 – mwt

+0

私は彼が示した最後の方法、すなわちパラメータ化されたモジュール、good_styleを使用していない方法を指していました。 Archaelusはまた、パラメータ化されたモジュールを使用している間はかなりフィットしているとコメントしています。あなたが使用したスタイルであるあなたの例のスタイルを決して使用しようとしなかったとしても、 – rvirding

関連する問題