Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/go/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在Erlang进程中保存状态?_Erlang - Fatal编程技术网

如何在Erlang进程中保存状态?

如何在Erlang进程中保存状态?,erlang,Erlang,我正在学习Erlang,并试图弄清楚如何在进程内保存状态 例如,我试图编写一个程序,在文件中给出一个数字列表,告诉我该文件中是否出现了一个数字。我的方法是使用两个过程 缓存将文件内容读取到一个集合中,然后等待数字检查,然后答复它们是否出现在集合中 is_member_loop(Data_file) -> Numbers = read_numbers(Data_file), receive {From, Number} -> F

我正在学习Erlang,并试图弄清楚如何在进程内保存状态

例如,我试图编写一个程序,在文件中给出一个数字列表,告诉我该文件中是否出现了一个数字。我的方法是使用两个过程

  • 缓存将文件内容读取到一个集合中,然后等待数字检查,然后答复它们是否出现在集合中

    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\u loop
,而不是文件名。这似乎是Erlang中的一个常见习语,在精彩的在线书籍中有一个很好的例子


但是,我认为,对于我希望在流程中保留的更复杂的状态,问题仍然存在。

简单的解决方案是,您可以将数字列表而不是文件名传递给函数
is_member_loop(Data_file)

处理状态时的最佳解决方案是使用gen_服务器。要了解更多信息,您应该查看和(可能也很有用)

实际上:

1) 从基于gen_服务器行为的模块(yourmodule.erl)开始 2) 在gen_服务器的init函数中读取文件,并将其作为状态字段传递:

init([]) ->
    Numbers = read_numbers(Data_file),
{ok, #state{numbers=Numbers}}.
3) 编写一个函数,用于触发对gen_服务器的调用

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函数导出
检查编号

-export([check_number/1]).
关于第4点,需要解释两件事:

a) 我们使用模式匹配来提取记录状态中的值

b) 正如您可能看到的,我留下了通用句柄调用,否则,每当收到与{check_number,number}不同的消息时,gen_服务器将由于错误的模式匹配而失败


注意:如果您是erlang新手,请不要使用process dictionary,因为我还不是erlang专业人士,所以不确定这有多惯用,但我会使用。基本上

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\u成员定义为

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.

您的
is\u member\u loop
将使用表的id进行查找,而不是使用
数据文件

我几乎觉得自己很愚蠢,没有想到将列表本身作为参数而不是文件名传递。我在考虑流程字典,因为在中,Joe Armstrong在他的一个示例中使用了它。我在网上读到,这是一种令人沮丧的做法,因此我提出了问题。最后,我是一个新手,还没有接触到OTP部分,但
gen_服务器
似乎确实是更好的方法。ets是一个解决方案,但您必须小心,因为如果所有者进程崩溃,您的ets表也将丢失。