问题
I am writing code that reads two input files and checks if the words in the first file are present in the second file. I want to check elements of the list one by one via process message passing.
Here is my code:
start()->
Pid2 = spawn(?MODULE,check2,[]),
spawn(?MODULE,check1,[Pid2]).
check1(Pid2) ->
{ok, Data} = file:read_file("input.txt"),
B = binary:split(Data, [<<" ">>], [global]),
K = [binary_to_list(Item) || Item <- B],
[Pid2 ! Element || Element <- K].
check2() ->
{ok,IoDevice} = file:open("check.txt", [read]),
L = string:tokens(io:get_line(IoDevice,""), "! ."),
receive
Element ->
case lists:member(Element,L)of
true ->
io:format(Element);
false ->
io:format("not_ok")
end
end.
The problem is that when I want to send an element of the list, it sends just the first element. How can I modify my code to send all strings and check them?
回答1:
The primary issue is that your check2/0
function only receives a single element and then exits. It needs to loop to receive all elements, and it also needs something to tell it when to stop. Let's change the functions one by one below, starting with start/0
:
start()->
Pid2 = spawn(?MODULE,check2,[]),
check1(Pid2).
The change here is that there's no need to spawn check2/1
— it can just be run directly by start/0
.
Next, here's our revised check1/1
function:
check1(Pid2) ->
{ok, Data} = file:read_file("input.txt"),
B = binary:split(Data, [<<" ">>,<<"\n">>], [global,trim_all]),
K = [binary_to_list(Item) || Item <- B],
[Pid2 ! Element || Element <- K++[stop]].
First, we added newline to the split pattern, and also the trim_all
option to get rid of empty elements from the split. We also appended the atom stop
to the list of elements we send to Pid2
. Let's look at our revised check2/0
function to see why:
check2() ->
{ok,IoDevice} = file:open("check.txt", [read]),
L = string:tokens(io:get_line(IoDevice,""), "! .\n"),
check2(L).
Note that we've split the original check2/0
into two functions: check2/0
and check2/1
. This is because the check2/1
function has to be recursive so it can receive all the elements sent to it:
check2(L) ->
receive
stop ->
ok;
Element ->
case lists:member(Element,L)of
true ->
io:format("found: ~s\n", [Element]);
false ->
io:format("not found: ~s\n", [Element])
end,
check2(L)
end.
Notice that inside the receive
we first check to see if we've received the atom stop
, and if we do, we exit the function. Otherwise, we receive and check an Element
, and after that call check2/1
recursively so it can receive either the next Element
or the stop
atom.
来源:https://stackoverflow.com/questions/34979403/erlang-message-passing-between-process