Programming Erlang(2nd, Armstrong) стр.15-18: Почему оболочка зависает после второго приема?

Вот мой код:

-module(afile_server).
-export([start/1, loop/1]).

start(Dir) -> 
    spawn(afile_server, loop, [Dir]).

loop(Dir) ->
    receive
        {Client, list_files} -> 
            Client ! {self(), file:list_dir(Dir)};
        {Client, {get_file, File}} -> 
            Full = filename:join(Dir, File),
            Client ! {self(), file:read_file(Full)}
    end,
    loop(Dir).

Вот команды оболочки:

$ erl
Erlang/OTP 17 [erts-6.4] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V6.4  (abort with ^G)

2> c(afile_server).
{ok,afile_server}

3> Server = afile_server:start(".").
<0.43.0>

4> Server ! {self(), list_files}.
{<0.32.0>,list_files}

5> receive X -> X end. 
{<0.43.0>,
 {ok,["afile_client.erl","afile_server.beam",
      "afile_server.erl","hello.beam","hello.erl","old"]}}

6> Server ! {self(), {get_file, "hello.erl"}}.
{<0.32.0>,{get_file,"hello.erl"}}

7> receive X -> X end.

<hangs>

person 7stud    schedule 28.01.2017    source источник


Ответы (1)


Хорошо, я нашел ответ здесь:

http://erlang.org/pipermail/erlang-questions/2007-April/026121.html

Спасибо Андерс Нюгрен!

Для первого приема X начинается без привязки, и он будет соответствовать чему угодно. Когда первый прием проверяет сообщение с файлового сервера, X привязывается к сообщению, что является значением:

 {ok,["afile_client.erl","afile_server.beam",
      "afile_server.erl","hello.beam","hello.erl","old"]}}

Во втором приеме X уже связан, поэтому прием ищет совпадение с:

 {ok,["afile_client.erl","afile_server.beam",
      "afile_server.erl","hello.beam","hello.erl","old"]}}

Второй прием зависает, потому что сообщение, отправленное файловым сервером:

{ok,<<"-module(hello).\n-export([start/0]).\n\nstart() ->
    io:format(\"hello world~n\").\n">>}}

который не соответствует X (соответствие ok совпадает, но после этого совпадения нет).

Решение состоит в том, чтобы использовать другую переменную для второго приема:

7> receive Y -> Y end.
person 7stud    schedule 28.01.2017
comment
В то время как в функции модуля вы должны использовать блок получения для доступа к сообщениям, в оболочке есть предопределенная функция, которая печатает все сообщения, полученные до сих пор: flush(), она также немедленно возвращается, если очередь сообщений пуста. Если вы хотите прочитать одно сообщение, вам нужно использовать свой метод, вы можете воспользоваться тем, что назначение переменных моделируется в оболочке, поэтому можно забыть одно: f(X) и X будут считаться несвязанными - person Pascal; 28.01.2017
comment
@Pascal, спасибо за советы. - person 7stud; 29.01.2017