gen_serverノート
7499 ワード
gen_serverノート
by cn Denis http://cndenis.iteye.com 2013年4月24日
gen_ServerはerlangのOTPフレームの中で最もよく使われている「行動パターン」ですよね.少なくともいくつかのerlang教材はまずこれを紹介します.
これは何に使いますか?それとも、なぜこれを使うのですか?このことについては、まだ数日間しか触れていないので、理解はまだ浅いです.serverには以下のいくつかのメリットがあります.
像に向かって、データと方法をカプセル化します.gen_server内部は状態Stateを維持し、他の言語の「クラス」のように、データと方法を一緒にパッケージして、データが不正に変更されるのを防ぐために、各種の関数を提供する必要があります.コールを簡略化し、通信を遮断する.erlangでは、遠隔プロセス呼び出し(RPC)を自分で実現するためには、メッセージフォーマットを自分で定義し、パッケージとデバッグのコードを自分で作成し、さらに各種の異常問題を処理する必要があります.Serverは全部できました.普通の使用関数のように直接調整すればいいです.手間が省けます.まだ間違いがありません.熱コード置換などの高級機能.ホットコードの交換はerlangが宣伝している特徴的な機能です.停止せずに生産を維持することはとても素晴らしいことです.でも、これは高級機能です.初学はまだ使えません.本でも多く話していません.gen_serverテンプレート
gen_serverはテンプレートを使って書いてもいいです.以下の通りです.
-moduleはモジュール名で、ファイル名です.
-behaviourは「行動パターン」を指定しています.ここでgen_です.serverは、このモジュールがgen_が実現されているかどうかを確認するのに役立ちます.serverのすべてのインターフェース.つまり
-exportは二つあります.一つ目にAPIと書いてあります.つまり他の人のためのインターフェースです.二つ目はgen_です.serverのインターフェースは、上で言った六つです.本当は同じexportに書いてもいいですが、別々に書いたほうがいいです.
次に、各API関数があります.一般的にはパッケージ化、コールバック関数の包装関数です.
後は六つのコールバック関数の具体的な実現です.コールバック関数は具体的な仕事を担当します.
このような比喩をすることができるでしょう.もしモジュール全体が昆虫であれば、APIは頭で、gen_serverは体ですが、リフティング関数は六本足です.頭にどこに行くかと言ったら、足を動かして、虫を全部走らせます.体はそれぞれの足をくっつけているので、さもなくば単独の足はもとの場所で痙攣することしかできなくて、どこにもいけません.
サーバを起動
サーバーを起動するには
start関数は、4つのパラメータ
最初のパラメータ
第二のパラメータ
注意したいのは、API関数とコールバック関数は、慣習的には同じファイルに書かれていますが、実行関数のプロセスは通常は違っています.上記のテンプレートで
サーバを使う
三つのハンドルの先頭のコールバック関数は三つの異なるサーバーを使用する方式に対応しています.以下のとおりです
コール
コールは戻り値のコールであり、同期コールとも言われています.コールバック関数が戻ってくるまで、プロセスは呼び出された後、待ち続けます.その関数形式は
第1のパラメータ
最後のパラメータ
コールは、コールバック関数
callを使う時に注意しなければならないのは、2つのサーバーのプロセスはお互いにcallしないとロックされます.
cast
castは戻り値のない呼び出しで、一般的には通知と呼ばれています.これは「非同期」の呼び出しです.呼び出し後に直接届きます.
その形式は
マルチノードの場合、
castたちの対応するコールバック関数は
生の知らせ
生メッセージとは、コールやcastを通じて直接サーバーに送信しないというメッセージで、一部の本には「メッセージ付き」と訳されています.例えば、ネットソケットのsocketからのメッセージ、他のプロセス用!送ってきたメッセージ、サーバとのリンクを作るプロセスが死んでしまいました.
生メッセージは
サーバを停止
上記で紹介されたhandle関数は、「stop」に戻ると、コールバック関数
一番簡単なのは何もしないで、okに戻るといいです.
参考資料とリソース:
gen_serverの文書
OTP設計原則におけるgen_serverの紹介
by cn Denis http://cndenis.iteye.com 2013年4月24日
gen_ServerはerlangのOTPフレームの中で最もよく使われている「行動パターン」ですよね.少なくともいくつかのerlang教材はまずこれを紹介します.
これは何に使いますか?それとも、なぜこれを使うのですか?このことについては、まだ数日間しか触れていないので、理解はまだ浅いです.serverには以下のいくつかのメリットがあります.
像に向かって、データと方法をカプセル化します.gen_server内部は状態Stateを維持し、他の言語の「クラス」のように、データと方法を一緒にパッケージして、データが不正に変更されるのを防ぐために、各種の関数を提供する必要があります.コールを簡略化し、通信を遮断する.erlangでは、遠隔プロセス呼び出し(RPC)を自分で実現するためには、メッセージフォーマットを自分で定義し、パッケージとデバッグのコードを自分で作成し、さらに各種の異常問題を処理する必要があります.Serverは全部できました.普通の使用関数のように直接調整すればいいです.手間が省けます.まだ間違いがありません.熱コード置換などの高級機能.ホットコードの交換はerlangが宣伝している特徴的な機能です.停止せずに生産を維持することはとても素晴らしいことです.でも、これは高級機能です.初学はまだ使えません.本でも多く話していません.gen_serverテンプレート
gen_serverはテンプレートを使って書いてもいいです.以下の通りです.
-module().
-behaviour(gen_server).
%% API
-export([]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
terminate/2, code_change/3]).
-define(SERVER,?MODULE).
start_link() ->
gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
init([]) ->
{ok, State}.
handle_call(_Request, _From, State) ->
{reply, Reply, State}.
handle_cast(_Msg, State) ->
{noreply, State}.
handle_info(_Info, State) ->
{noreply, State}.
terminate(_Reason, _State) ->
ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
意味は以下の通りです-moduleはモジュール名で、ファイル名です.
-behaviourは「行動パターン」を指定しています.ここでgen_です.serverは、このモジュールがgen_が実現されているかどうかを確認するのに役立ちます.serverのすべてのインターフェース.つまり
init/1
、 handle_call/3
、handle_cast/2
、 handle_info/2
、 terminate/2
、 code_change/3
の6つの関数.足りないとコンパイラがエラーします.-exportは二つあります.一つ目にAPIと書いてあります.つまり他の人のためのインターフェースです.二つ目はgen_です.serverのインターフェースは、上で言った六つです.本当は同じexportに書いてもいいですが、別々に書いたほうがいいです.
次に、各API関数があります.一般的にはパッケージ化、コールバック関数の包装関数です.
後は六つのコールバック関数の具体的な実現です.コールバック関数は具体的な仕事を担当します.
このような比喩をすることができるでしょう.もしモジュール全体が昆虫であれば、APIは頭で、gen_serverは体ですが、リフティング関数は六本足です.頭にどこに行くかと言ったら、足を動かして、虫を全部走らせます.体はそれぞれの足をくっつけているので、さもなくば単独の足はもとの場所で痙攣することしかできなくて、どこにもいけません.
サーバを起動
サーバーを起動するには
start/3
、start/4
、start_link/3
、start_link/4
、{ok,Pid}
の四つの関数があります.これらのstart関数を使うと、新しいプロセスが生まれます.つまり、一つのgen_です.serverサーバー.これらのstart関数の通常の場合の戻り値はPid
であり、(ServerName, Module, Args, Options)
はこの新しいプロセスのプロセス番号である.Linkと持たないの違いは、親プロセスとリンクしているかどうかということです.言い換えれば、新起動のプロセスが死んだら、彼のプロセス(親プロセス)を起動することを知らせますか?start関数は、4つのパラメータ
ServerName
とすることができる.最初のパラメータ
{error, {already_started, Pid}}
はサービス名であり、省けます.同じサービス名を持つモジュールは一つのノードで一回しか起動できません.繰り返し起動するとエラーが発生します. -define(SERVER, ?MODULE)
.サービス名を持つサービスのプロセスは、名来で呼び出すことができます.サービス名がないのは、プロセス番号pidでしか呼び出しられません.通常名前のサービスプロセスは、モジュール名をサービス名として使用し、上のテンプレートで定義されたマクロ?SERVER
を使用して、サービス名が必要なところにModule
を記入します.第二のパラメータ
?MODULE
はモジュール名です.一般的にAPIとコールバック関数は同じファイルに書いてあります. Args
は、本モジュールのモジュール名を表します.第3のパラメータinit/1
は、コールバック関数init/1
のパラメータであり、そのままOptions
に伝えられる.4番目のパラメータinit/1
はいくつかのオプションであり、debug、タイムアウトなどのものを設定することができます.startは対応するコールバック関数init/1
であり、一般的にはサーバー起動後の初期化作業を行い、初期の状態Stateを生成し、正常復帰は{ok,State}である.このStateはサーバー全体を通して、六つのコールバック関数を結びつけるきずなです.その値は最初にinit/1
によって生成され、その後、3つのhandle関数によって修正され、毎回修正された後、また戻り値に戻して、次の呼出されるhandle関数に使用される.ignore
が{stop, Reason}
またはstart_link/0
に戻ると、サーバの起動は中止される.注意したいのは、API関数とコールバック関数は、慣習的には同じファイルに書かれていますが、実行関数のプロセスは通常は違っています.上記のテンプレートで
self()
を使用すると、調整者のプロセス番号が表示され、init/1
にself()
を使用すると、サーバのプロセス番号が表示される.サーバを使う
三つのハンドルの先頭のコールバック関数は三つの異なるサーバーを使用する方式に対応しています.以下のとおりです
gen_server:call ------------- handle_call/3
gen_server:cast ------------- handle_cast/2
! ------------- handle_info/2
コールは戻り値の呼び出しがあります.castは戻り値なしの呼び出し、すなわち通知である.直接サーバーのプロセスに送るメッセージはhandle_から送られます.info処理コール
コールは戻り値のコールであり、同期コールとも言われています.コールバック関数が戻ってくるまで、プロセスは呼び出された後、待ち続けます.その関数形式は
gen_server:call(ServerRef, Request, Timeout) -> Reply
、第1のパラメータ
ServerRef
は、起動されたサーバであり、サーバ名またはサーバのpidである.第二のパラメータRequest
は、コールバック関数handle_call
に直接伝達される.最後のパラメータ
Timeout
はタイムアウトであり、省略可能であり、デフォルト値は5秒である.マルチノードの場合、multi_call
に使用されて、各ノードに同じ登録名を持つサービスプロセスから呼び出しを開始する機会がある.(この関数の文書上の表現はちょっと分かりにくいです.詳しくは ここです)コールは、コールバック関数
handle_call/3
の動作を指示するために使用されます.具体的な形式は handle_call(Request, From, State)
最初のパラメータRequest
は、callによって送られてきたもので、プログラムを書く際の関心と処理の重点である.第二のパラメータFrom
はgen_である.Serverが伝えたのは、コールの元、つまりどのプロセスがコールを実行しましたか? From
の形式は{Pid, Ref}
で、Pid
はソースプロセス番号であり、Ref
は呼び出しの識別子であり、毎回呼び出しは違っていて、区別するために用いられる.Pidがあれば、ソースプロセスにメッセージを送る必要があるときに使用できますが、コールは戻り値があるので、戻り値を使ってデータを転送するのが一般的です.第3のパラメータState
はサーバの状態であり、これはinitまたは他のhandle関数によって生成され、必要に応じて修正した後、戻り値に戻すことができる.コール対応のコールバック関数handle_call/3
は、通常の場合の戻り値{reply, Reply, NewState}
である. Reply
は、コールの戻り値として伝えられ、NewState
はサーバの状態となる.また、{stop, Reasion, State}
を使用してサーバの動作を中止することもできます.これは比較的少ないです.callを使う時に注意しなければならないのは、2つのサーバーのプロセスはお互いにcallしないとロックされます.
cast
castは戻り値のない呼び出しで、一般的には通知と呼ばれています.これは「非同期」の呼び出しです.呼び出し後に直接届きます.
ok
、コールバック関数の実行が完了するまで待つ必要はない.その形式は
gen_server:cast(ServerRef, Request)
です.パラメータの意味はコールと同じです.戻りを待つ必要はないので、タイムアウトを設定する必要はありません.3番目のパラメータはありません.マルチノードの場合、
abcast
を用いて、各ノードに指定された名前のサービスプロセスに通知することができる.(不思議なことに、なぜmulti_cast
と呼ばないですか?multi_call
に似ているのに)castたちの対応するコールバック関数は
handle_cast/2
で、具体的にはhandle_cast(Msg, State)
です.一つ目のパラメータはcastで送りました.二つ目はサーバーの状態です.コールと似ています.多くは言いません.handel_cast/2
の戻り値は、一般的に{noreply, NewState}
であり、これはサーバの状態を変更するために使用されるか、または{stop, Reason, NewState}
であり、これはサーバを停止する.通常、サーバー停止命令はcastで実現することが多いです.生の知らせ
生メッセージとは、コールやcastを通じて直接サーバーに送信しないというメッセージで、一部の本には「メッセージ付き」と訳されています.例えば、ネットソケットのsocketからのメッセージ、他のプロセス用!送ってきたメッセージ、サーバとのリンクを作るプロセスが死んでしまいました.
{'EXIT', Pid, Why}
などを送ってきました.普通はプログラムを書く時、できるだけAPIを使って、直接に使わないでください.サーバプロセスにメッセージを送るが、メッセージに依存するアプリケーションのようなsocketに対しては、生メッセージを処理しなければならない.生メッセージは
handle_info/2
を用いて処理され、具体的にはhandle_info(Info, State)
である.その中でInfoは送ってきたメッセージの内容です.回答はhandle_cast
と同じです.サーバを停止
上記で紹介されたhandle関数は、「stop」に戻ると、コールバック関数
terminate/2
を使用してバックグラウンド動作を行います.一般的には、開いているリソース、ファイル、ネットワーク接続をオフにして、ログを記録し、他のプロセスに「私は死にました」または「信春哥、満血復活」を通知します.一番簡単なのは何もしないで、okに戻るといいです.
参考資料とリソース:
gen_serverの文書
OTP設計原則におけるgen_serverの紹介