7

私はErlangを学んでおり、プロセス内で状態を保存する方法と保存する方法を理解しようとしています.

たとえば、ファイル内の数値のリストを指定して、そのファイルに数値が含まれているかどうかを通知するプログラムを作成しようとしています。私のアプローチは、2つのプロセスを使用することです

  • ファイルの内容をセットに読み込み、数字がチェックされるのを待ってから、それらがセットに含まれているかどうかを返信するキャッシュ。

    is_member_loop(Data_file) ->
        Numbers = read_numbers(Data_file),
        receive
            {From, Number} ->
                From ! {self(), lists:member(Number, Numbers)},
                is_member_loop(Data_file)
        end.
    
  • 番号をキャッシュtrueに送信し、またはfalse応答を待機するクライアント。

    check_number(Number) ->
        NumbersPid ! {self(), Number},
        receive
            {NumbersPid, Is_member} ->
                Is_member
        end.
    

ファイルはリクエストごとに読み取られるため、このアプローチは明らかに単純です。しかし、私はErlangにまったく慣れていないため、異なるリクエスト間で状態を維持するための好ましい方法が何であるかは不明です.

プロセス辞書を使用する必要がありますか? そのようなプロセス状態について、私が認識していない別のメカニズムはありますか?

アップデート

user601836で提案されているように、最も明白な解決策は、一連の数値をis_member_loopファイル名の代わりにパラメーターとして渡すことです。これは Erlang の一般的なイディオムのようで、素晴らしいオンライン ブックLearn you some Erlangに良い例があります。

ただし、プロセスで保持したいより複雑な状態についても、問題は依然として当てはまると思います。

4

2 に答える 2

10

is_member_loop(Data_file)簡単な解決策として、ファイル名ではなく数値のリストを関数に渡すことができます。

状態を扱うときの最善の解決策は、gen_server を使用することです。詳細については、レコードgen_server の動作を確認する必要があります(これも役立つ場合があります)。

実際には:

1) gen_server の動作に基づいたモジュール (yourmodule.erl) から開始します 2) gen_server の init 関数でファイルを読み取り、状態フィールドとして渡します。

init([]) ->
    Numbers = read_numbers(Data_file),
{ok, #state{numbers=Numbers}}.

3) gen_server への呼び出しをトリガーするために使用される関数を作成します。

check_number(Number) ->
    gen_server:call(?MODULE, {check_number, Number}).

4) 関数からトリガーされたメッセージを処理するためのコードを記述します。

handle_call({check_number, Number}, _From, #state{numbers=Numbers} = State) ->
    Reply = lists:member(Number, Numbers)},
{reply, Reply, State};

handle_call(_Request, _From, State) ->
    Reply = ok,
{reply, Reply, State}.

5) yourmodule.erl 関数からのエクスポートcheck_number

-export([check_number/1]).

ポイント4について説明する2つのこと:

a) パターン マッチングを使用してレコード State 内の値を抽出します

b) ご覧のとおり、ジェネリック ハンドル コールを残しました。そうしないと、{check_number, Number} とは異なるメッセージが受信されるたびに、間違ったパターン マッチングが原因で gen_server が失敗します。

注: erlang を初めて使用する場合は、プロセス ディクショナリを使用しないでください。

于 2012-05-17T12:10:36.183 に答える
2

私はまだErlangのプロではないので、これがどれほど慣用的なものかはわかりませんが、ETSを使用してこれを処理します。基本的、

read_numbers_to_ets(DataFile) ->
    Table = ets:new(numbers, [ordered_set]),
    insert_numbers(Table, DataFile),
    Table.

insert_numbers(Table, DataFile) ->
    case read_next_number(DataFile) of
    eof -> ok;
    Num -> ets:insert(numbers, {Num})
    end.

is_member次に、次のように定義できます

is_member(TableId, Number) ->
    case ets:match(TableId, {Number}) of
    [] -> false; %% no match from ets
    [[]] -> true %% ets found the number you're looking for in that table
    end.

を取得する代わりに、ルックアップを行うテーブルの ID を取得しますData_fileis_member_loop

于 2012-05-17T13:59:42.883 に答える