2011-06-20 2 views
4

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

Учитывая этот простой код, в котором функция 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, которое связывает присвоение переменной в таких случаях, но такая привязка не предлагается для передачи аргументов?


EDIT:

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

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}}, 
... 

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

ответ

8

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

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

+0

Итак, «системный планировщик» == «не потеть детали». Я могу справиться с этим. Сначала я прочитал документы, и именно это изначально заставило меня задуматься об этом. Я задавался вопросом, почему именно я создаю 'a/0', но получаю PID для' b/0'. Я имею в виду, что это было желаемое поведение, но я не мог понять его механику. Я думаю, Erlang просто знает, какой PID вернется в этом сценарии. – user113716

+6

Pid не меняется - он «указывает» на процесс, который работает. По мере запуска он выполняет разные функции (в вашем случае A, затем B). 'current_function' показывает только, какую функцию выполняет этот процесс в тот момент, когда вы вызываете' process_info/1'. Если вам удастся взглянуть на него сразу, это будет в 'a/0', но если вы дадите ему достаточно долго, оно будет в' b/0'. –

+2

Ах !!! Мое мышление было неправильным (очевидно). У меня было в голове, что когда вы создаете процесс (ссылаясь на функцию в 'spawn/3'), каждая функция, вызванная по пути, будет иметь свой собственный уникальный PID, связанный с ней. Но вместо этого процесс является более широким и может включать вызов многих функций, а PID - это просто ссылка на общий «процесс», который происходит. Если это звучит правильно (хотя и неуклюже поставлено), то я считаю, что понимаю. – user113716

6

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

Смежные вопросы