Erlang Message passing between process

2019-09-20 09:31发布

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条回答
神经病院院长
2楼-- · 2019-09-20 10:21

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.

查看更多
登录 后发表回答