Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Erlang - spawning processes and passing arguments

Tags:

erlang

I keep running into this. I want to spawn processes and pass arguments to them without using the MFA form (module/function/arguments), so basically without having to export the function I want to spawn with arguments. I've gotten around this a few times using closures(fun's) and having the arguments just be bound values outside the fun(that I then reference inside the fun), but its limiting my code structure... I've looked at the docs and spawn only has the regular spawn/1 and the spawn/3 form, nothing else...

I understand that code reloading in spawned processes is not possible without the use of the MFA form but the spawned processes are not of the long running nature and finish relatively quickly so that's not an issue (I also want to contain all the code in one module-level function with sub-jobs being placed in funs inside that function).

much appreciated thanks

like image 945
deepblue Avatar asked Feb 20 '09 21:02

deepblue


3 Answers

This is an old question but I believe it can be properly answered with a bit of creativity:

The goal of the question is to

  • Invoke a function

With the following limits;

  • No M:F/A formatting
  • No exporting of the Invoked function

This can be solved in the following;

Using the 1st limitation leads us to the following solution:

run() ->
    Module = module,
    Function = function,
    Args = [arg1, arg2, arg3],
    erlang:spawn(Module, Function, Args).

In this solution however, the function is required to be exported.

Using the 2nd limitation (No exporting of the Invoked function) alongside the 1st leads us to the following solution using conventional erlang logic:

run() ->
    %% Generate an anonymous fun and execute it
    erlang:spawn(fun() -> function(arg1, arg2, arg3) end).

This solution generates Anonymous Funs every execution which may or may not be wanted based on your design due to the extra work that the Garbage Colelctor will need to perform (note that, generally, this will be neglible and issues will potentially only be seen in larger systems).

An alternative way to write the above without generating Anonymous Funs would be to spawn an erlang:apply/2 which can execute functions with given parameters.

By passing a Function Ref. to erlang:apply/2, we can reference a local function and invoke it with the given arguments.

The following implements this solution:

run() ->
    %% Function Ref. to a local (non-exported) function
    Function = fun function/arity,
    Args = [arg1, arg2, arg3],
    erlang:spawn(erlang, apply, [Function, Args]).

Edit: This type of solution can be found within the Erlang Src whereby erlang:apply/2 is being called to execute a fun() with args.

%% https://github.com/erlang/otp/blob/71af97853c40d8ac5f499b5f2435082665520642/erts/preloaded/src/erlang.erl#L2888%% Spawn and atomically set up a monitor.

-spec spawn_monitor(Fun) -> {pid(), reference()} when
      Fun :: function().
spawn_monitor(F) when erlang:is_function(F, 0) ->
    erlang:spawn_opt(erlang,apply,[F,[]],[monitor]);
spawn_monitor(F) ->
    erlang:error(badarg, [F]).
like image 66
artman41 Avatar answered Sep 18 '22 15:09

artman41


actually Richard pointed me in the right direction to take to avoid the issue nicelly (in a reply to the same post I put up on the Erlang GoogleGroups): http://groups.google.com/group/erlang-programming/browse_thread/thread/1d77a697ec67935a

His answer:

By "using closures", I hope you mean something like this:

Pid = spawn(fun () -> any_function(Any, Number, Of, Arguments) end)

How would that be limiting to your code structure?

 /Richard 

thank you for promptly commenting you my question. Much appreciated

like image 33
deepblue Avatar answered Sep 21 '22 15:09

deepblue


Short answer: you can't. Spawn (in all it's varying forms) only takes a 0-arity function. Using a closure and bringing in bound variables from the spawning function is the way to go, short of using some sort of shared data store like ETS (which is Monster Overkill).

I've never found using a closure to severely hamper my code structure, though; can you give an example of the problems you're having, and perhaps someone can tidy it up for you?

like image 2
womble Avatar answered Sep 21 '22 15:09

womble