Понимание возвращаемого значения spawn

Я начинаю работать с Erlang, и мне не помешала бы небольшая помощь в понимании различных результатов при применении PID, возвращаемого из spawn/3, в метод process_info/1.

Учитывая этот простой код, в котором экспортируется функция a/0, которая просто вызывает b/0, ожидающую сообщения:

-module(tester).
-export([a/0]).

a() ->
    b().
b() ->
    receive {Pid, test} ->
        Pid ! alrighty_then
    end.

... пожалуйста, помогите мне понять причину другого вывода из оболочки:


Пример 1:

Здесь current_function из Pid показано как tester:b/0:

Pid = spawn(tester, a, []).

process_info( Pid ).

> [{current_function,{tester,b,0}},
    {initial_call,{tester,a,0}},
    ...

Пример 2:

Здесь current_function из process_info/1 показано как tester:a/0:

process_info( spawn(tester, a, []) ).

> [{current_function,{tester,a,0}},
    {initial_call,{tester,a,0}},
    ...

Пример 3:

Здесь current_function из process_info/1 показано как tester:a/0, но current_function из Pid равно tester:b/0:

process_info( Pid = spawn(tester, a, []) ).

> [{current_function,{tester,a,0}},
    {initial_call,{tester,a,0}},
    ...

process_info( Pid ).

> [{current_function,{tester,b,0}},
    {initial_call,{tester,a,0}},
    ...

Я предполагаю, что при вызове spawn/3 в фоновом режиме происходит какой-то асинхронный код, но как работает назначение переменных и передача аргументов (особенно в последнем примере), так что Pid получает одно значение, а process_info/1 получает другое?

Есть ли в Erlang что-то особенное, что связывает присваивание переменных в таких случаях, но для передачи аргументов такая привязка не предлагается?


ИЗМЕНИТЬ:

Если я использую такую ​​функцию:

TestFunc = fun( P ) -> P ! {self(), test}, flush() end.

TestFunc( spawn(tester,a,[]) ).

... сообщение возвращается правильно от tester:b/0:

Shell got alrighty_then
ok

Но если я использую такую ​​функцию:

TestFunc2 = fun( P ) -> process_info( P ) end.

TestFunc2( spawn(tester,a,[]) ).

... process_info/1 по-прежнему показывает tester:a/0:

[{current_function,{tester,a,0}},
 {initial_call,{tester,a,0}},
 ...

Не знаю, что со всем этим делать. Возможно, мне просто нужно смириться с тем, что это выше моей зарплаты!


person user113716    schedule 20.06.2011    source источник


Ответы (2)


Если вы посмотрите на документы для spawn, там сказано, что он возвращает вновь созданный Pid и помещает новый процесс в очередь системного планировщика. Другими словами, процесс запускается, но вызывающий процесс продолжает выполняться.

Erlang отличается от некоторых других языков тем, что вам не нужно явно передавать управление, а скорее вы полагаетесь на планировщик процессов, чтобы определить, когда какой процесс выполнять. В тех случаях, когда вы выполняли назначение Pid, у планировщика было достаточно времени, чтобы переключиться на порожденный процесс, который впоследствии вызывал b/0.

person David Weldon    schedule 20.06.2011
comment
Так что системный планировщик == не парьтесь в деталях. Я могу справиться с этим. Сначала я прочитал документы, и именно это изначально заставило меня задуматься об этом. Мне было интересно, почему я порождаю a/0, но получаю PID для b/0. Я имею в виду, что это, безусловно, было желаемым поведением, но я не мог понять его механику. Я думаю, Erlang просто знает, какой PID вернуть в этом сценарии. - person user113716; 21.06.2011
comment
Pid не меняется — он указывает на запущенный процесс. Во время работы он выполняет разные функции (в вашем случае A, затем B). current_function показывает только, какую функцию этот процесс выполняет в тот момент, когда вы вызываете process_info/1. Если вам удастся просмотреть его сразу, он будет в a/0, но если вы продержитесь достаточно долго, он будет в b/0. - person David Weldon; 21.06.2011
comment
Ах!!! Мое мнение было неправильным (очевидно). У меня было в голове, что когда вы создаете процесс (путем ссылки на функцию в spawn/3), каждая функция, вызываемая по пути, будет иметь свой собственный уникальный PID, связанный с ней. Но вместо этого процесс шире и может включать в себя вызов многих функций, а PID — это просто ссылка на общий процесс, который происходит. Если это звучит правильно (хотя и неуклюже изложено), то я, кажется, понимаю. - person user113716; 21.06.2011

Это действительно очень просто. Выполнение порожденного процесса начинается с вызова a(), который в какой-то момент вскоре после этого вызовет b(), а затем просто сидит и ждет, пока не получит определенное сообщение. В примерах, где вам удается немедленно вызвать process_info для pid, вы перехватываете его, пока процесс все еще выполняет a(). В других случаях, когда возникает некоторая задержка, вы перехватываете ее после вызова b(). Что в этом смущает?

person YOUR ARGUMENT IS VALID    schedule 20.06.2011