我正在学习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_loop
而不是文件名。它似乎是Erlang中常见的习语,在精彩的在线书Learn you some Erlang中有一个很好的例子。
但是,我认为,问题仍然适用于我希望在我的流程中保留的更复杂的状态。
答案 0 :(得分:8)
简单的解决方案,您可以将数字列表传递给函数is_member_loop(Data_file)
,而不是文件名。
处理状态时的最佳解决方案是使用gen_server。要了解详情,请查看records和gen_server behaviour(this也可能有用)。
在实践中:
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点需要解释的两件事:
a)我们使用模式匹配
提取记录状态中的值b)如您所见,我离开了通用句柄调用,否则只要收到与{check_number,Number}不同的消息,您的gen_server就会因错误的模式匹配而失败
注意:如果您不熟悉erlang,请不要使用进程字典
答案 1 :(得分:1)
不确定这是多么惯用,因为我还不是一个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.
您的Data_file
不会使用is_member_loop
,而是会使用表格的ID来进行查找。