2016-08-30 2 views
0

В Erlang можно вызвать некоторую функцию f (BIF или нет), чья задача - запустить процесс, запустить функцию argf, которую я предоставил, t "return" до тех пор, пока argf не вернется и сделает это без использования предложения receive (причина этого в том, что f будет вызываться в gen_server, я не хочу загрязнять почтовый ящик gen_server).Erlang: вызвать процесс и ждать окончания без использования `receive`

Отрывок будет выглядеть следующим образом:

%% some code omitted ... 
F = fun() -> blah, blah, timer:sleep(10000) end, 
f(F), %% like `spawn(F), but doesn't return until 10 seconds has passed` 
%% ... 
+0

Для чего это необходимо? почему бы просто не запустить этот «fun()» из основного процесса? –

+0

@ A.Sarid передается многим клиентам параллельно (скажем, 5 процессов, каждый обрабатывает клиенты nbr_clients/5') –

+0

Ну, я не думаю, что вам нужно беспокоиться об использовании блока 'trap_exit' и' receive'. Передача сообщений является одной из главных вещей в Эрланге. Вы не будете «загрязнять» почтовый ящик. –

ответ

1

Вы не будете «загрязнять» почтовый ящик gen_servers, если вы создаете + дождитесь сообщения до вы возвращаетесь из вызова или броска. Более серьезная проблема заключается в том, что вы заблокируете gen_server, пока вы ждете завершения другого процесса. Путь к этому заключается не в том, чтобы явно не ждать, а возвращаться из вызова/приведения, а затем, когда сообщение о завершении приходит, обрабатывает его в handle_info/2, а затем выполняет то, что необходимо.

Если нерестится в handle_call и вы хотите вернуть «результат» этого процесса, вы можете отложить возврат к исходному вызову с handle_info, обрабатывая сообщение о завершении процесса.

Обратите внимание, что однако вы это сделаете gen_server:call имеет значение таймаута, неявное или явное, и если ответ не получен, он генерирует ошибку в вызывающем процессе.

+0

Я в конечном итоге использую предложение 'receive', создал функцию, подобную' pmap' (за исключением того, что она не собирает результат, просто подождите окончания). Что касается блокировки, если он не блокирует процесс вызова от приема сообщений, возможно, это нормально - я не хочу обрабатывать следующий запрос до тех пор, пока он не будет обработан в любом случае. Я также рассматривал ваш альтернативный подход, недостатком является то, что он вводит состояние (ok_to_accept_new_request или waiting_the_current_job to_be_done) между handle_cast (я использую приведение для передачи), и мне также приходится иметь дело с тайм-аутами, кажется, не стоит проблем. –

2

Единственный способ обмена данными между процессами проходит сообщение (конечно, вы можете рассмотреть вопрос опроса для конкретного ключа в ИТС или файл, но я не люблю это).

Если вы используете функцию spawn_monitor в F/1, чтобы запустить процесс F, а затем есть получать блок только сопоставления возможных системных сообщений от этого монитора:

f(F) -> 
    {_Pid, MonitorRef} = spawn_monitor(F),  
    receive 
     {_Tag, MonitorRef, _Type, _Object, _Info} -> ok 
    end. 

вы будете не испортить ваш gen_server почтовый ящик. Например, минимальный код, вы можете добавить тайм-аут (фиксированный или параметр), выполнить некоторый код при нормальном или завершении ошибки ...

+0

Угадайте, что вы правы в единственном способе общения между процессами, может быть, я делаю это неправильно. –

2

Главный способ связи с процессом в пространстве Erlang VM - это сообщение, передающееся с erlang:send/2 или erlang:send/3 функциями (псевдоним !). Но вы можете «взломать» Erlang и использовать несколько способов для общения через процесс.

Вы можете использовать erlang:link/1 для передачи статистики процесса, в основном используемого в случае, если ваш процесс умирает или закончился или что-то не так (исключение или выброс).

Вы можете использовать erlang:monitor/2, это похоже на erlang:link/1, за исключением того, что сообщение отправляется непосредственно в почтовый ящик процесса.

Вы также можете взломать Erlang и использовать какой-то внутренний путь (общий ETS/DETS/Mnesia таблицы) или использовать внешние методы (базы данных или другие подобные вещи). Это явно не рекомендуется и «уничтожает» философию Эрланга ... Но вы можете это сделать.

По-видимому, ваша проблема может быть решена с помощью поведения supervisor.supervisor поддержка многих strategies контролировать контролируемую процесс:

  • one_for_one: Если один дочерний процесс завершается и должен быть перезапущен, только что дочерний процесс влияет. Это стратегия перезапуска по умолчанию.
  • one_for_all: Если один дочерний процесс завершается и должен быть перезапущен, все остальные дочерние процессы завершаются, а затем все дочерние процессы перезапускаются.
  • rest_for_one: Если один дочерний процесс завершается и должен быть перезапущен, «остальное» дочерних процессов (то есть дочерние процессы после прекращенного дочернего процесса в порядке запуска) завершаются. Затем завершается дочерний процесс и все дочерние процессы после его перезапуска.
  • simple_one_for_one: Упрощенный супервизор one_for_one, где все дочерние процессы динамически добавляются экземплярами одного и того же типа процесса, то есть выполняется тот же код.

Вы также можете изменить или создать свою собственную стратегию Прораб с нуля или базы на supervisor_bridge.

Итак, чтобы подвести итог, вам нужен процесс, который ждет один или несколько завершающих процессов. Это поведение поддерживается с OTP, но вы также можете создать свою собственную модель. Для этого вам нужно предоставить общий статус каждому запущенному процессу, используя кэш или базу данных или когда ваш процесс порожден. Нечто подобное:

Fun = fun 
    MyFun (ParentProcess, {result, Data}) 
    when is_pid(ParentProcess) -> 
     ParentProcess ! {self(), Data}; 
    MyFun (ParentProcess, MyData) 
    when is_pid(ParentProcess) -> 
     % do something 
     MyFun(ParentProcess, MyData2) end. 

spawn(fun() -> Fun(self(), InitData) end). 

EDIT: забыл добавить пример без send/receive. Я использую таблицу ETS для хранения каждого результата из лямбда-функции. Эта таблица ETS устанавливается, когда мы запускаем этот процесс. Чтобы получить результат, мы можем выбрать данные из этой таблицы. Примечание. Ключом строки является идентификатор процесса процесса.

spawner(Ets, Fun, Args) 
    when is_integer(Ets), 
     is_function(Fun) -> 
    spawn(fun() -> Fun(Ets, Args) end). 

Fun = fun 
    F(Ets, {result, Data}) -> 
    ets:insert(Ets, {self(), Data}); 
    F(Ets, Data) -> 
    % do something here 
    Data2 = Data, 
    F(Ets, Data2) end. 
+0

Я не вижу, как это связано с супервизорами, и я не поддерживаю его OTP. –

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