Emma Ekheart
Emma Ekheart

Reputation: 1

Create multiple processes from map

I am trying to create multiple processes in Erlang. For each key in the map, I want to create a process.

I have tried using the fold operation. Below is the code snippet for the same:

CreateMultipleThreads = fun(Key,Value,ok) ->
    Pid = spawn(calculator, init_method, [Key,Value,self()])
end,
maps:fold(CreateMultiplThreads,[],Map).

When maps:fold(CreateMultiplThreads,[],Map) is executed, the program terminates with the following error :

init terminating in do_boot.

Upvotes: 0

Views: 204

Answers (2)

7stud
7stud

Reputation: 48589

init terminating in do_boot

Searching around for similar errors, it looks like that error could be caused by improper command line arguments or your file name conflicts with an erlang file name. Therefore, you would need to post how you are running your program.

Below is a working example that you might be able to adapt to your situation--including how to run it:

calculator.erl:

-module(calculator).
-compile(export_all).

init(X, Y, Pid) ->
    io:format("init() in Process ~w got args ~w, ~w, ~w~n",
              [self(), X, Y, Pid]).

my.erl:

-module(my).
-compile([export_all]).

go() ->
    FoldFunc = fun(Key, Value, Acc) ->
        Pid = spawn(calculator, init, [Key, Value, self()]),
        [Pid|Acc]  % Returns new value for Acc
    end,
    Map = #{a => 3, b => 7, c => 10},
    _Pids = maps:fold(FoldFunc, [], Map).  % [] is the initial value for Acc.

When you call a fold function, e.g. lists:foldl(), lists:foldr(), maps:fold(), you iterate over each value in a collection, like a list or map, and perform some operation with each value, then you accumulate the results of those operations, and the fold function returns the accumulated results.

In the shell:

~/erlang_programs$ erl
Erlang/OTP 20 [erts-9.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V9.3  (abort with ^G)

1> c(my).  
my.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,my}

2> c(calculator).
calculator.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,calculator}

3> Calculators = my:go().
init() in Process <0.80.0> got args a, 3, <0.64.0>
init() in Process <0.81.0> got args b, 7, <0.64.0>
init() in Process <0.82.0> got args c, 10, <0.64.0>
[<0.82.0>,<0.81.0>,<0.80.0>]  %Return value of my:go()

4> 

The reason you might want to accumulate the pids of the spawned processes is to receive messages that are tagged with the pids of the spawned processes. For instance, if you want to get results from each of the calculators, you might use a receive clause like this:

Pid = % One of the calculator pids

receive
   {Pid, Result} ->
       %Do something with result

where each calculator does this:

Pid ! {self(), Result}

Something like this:

calculator.erl:

-module(calculator).
-compile(export_all).

init(X, Y, Pid) ->
    io:format("init() in Process ~w got args ~w, ~w, ~w~n",
              [self(), X, Y, Pid]),

    RandNum = rand:uniform(5),  % time it takes to perform calc
    timer:sleep(RandNum * 1000),  % sleep 1-5 seconds
    Pid ! {self(), RandNum}.  % send back some result

my.erl:

-module(my).
-compile([export_all]).

go() ->
    FoldFunc = fun(Key, Value, Acc) ->
        Pid = spawn(calculator, init, [Key, Value, self()]),
        [Pid|Acc]
    end,
    Map = #{a => 3, b => 7, c => 10},
    Calculators = maps:fold(FoldFunc, [], Map),

    lists:foreach(fun(Calculator) -> 
            receive
                {Calculator, Result} -> 
                    io:format("Result from ~w is: ~w~n", [Calculator, Result])
            end
        end,
        Calculators
    ).

In the shell:

7> c(calculator).
calculator.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,calculator}

8> c(my).
my.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,my}

9> my:go().
init() in Process <0.107.0> got args a, 3, <0.64.0>
init() in Process <0.108.0> got args b, 7, <0.64.0>
init() in Process <0.109.0> got args c, 10, <0.64.0>
Result from <0.109.0> is: 5
Result from <0.108.0> is: 4
Result from <0.107.0> is: 3
ok

Upvotes: 0

Roger Lipscombe
Roger Lipscombe

Reputation: 91825

init terminating in do_boot is not your problem. This just means that something caused your node to fail to start. Erlang has a habit of printing out lots of error messages. Your actual error is probably a few lines (or even lots of lines) above this. Look there first.


With that said, I tried your code directly in the erl shell:

$ erl
1> CreateMultipleThreads =fun(Key,Value,ok)-> Pid = spawn(calculator, init_method, [Key,Value,self()]) end.
#Fun<erl_eval.18.128620087>
2> Map = #{k1 => v1, k2 => v2}.
#{k1 => v1,k2 => v2}
3> maps:fold(CreateMultipleThreads,[],Map).
** exception error: no function clause matching erl_eval:'-inside-an-interpreted-fun-'(k1,v1,[]) 
     in function  erl_eval:eval_fun/6 (erl_eval.erl, line 829)
     in call from maps:fold_1/3 (maps.erl, line 257)

What this is trying to tell you is that the function that you passed to maps:fold doesn't match the expected form -- no function clause matching <mangled-name> (k1,v1,[]).

It's attempting to pass (k1, v1, []), but your function is expecting (Key, Value, ok). The [] doesn't match the ok.

Where did the [] come from? It came from the accumulator value you initially passed to maps:fold. On each iteration, the previous result is passed as the new accumulator, so you need to think about how to keep it all matching.


If you genuinely don't want the result, just pass ok as the initial accumulator value, match ok, and make sure to return ok:

CreateMultipleThreads = fun(Key, Value, ok) ->
    Pid = spawn(calculator, init_method, [Key, Value, self()]),
    ok
end.
maps:fold(CreateMultipleThreads, ok, Map).

Or you can do something useful with the accumulator, such as collect the process IDs:

Map = #{k1 => v1, k2 => v2},
CreateMultipleThreads = fun(Key, Value, Acc)->
    Pid = spawn(calculator, init_method, [Key, Value, self()])
    [Pid | Acc]
end,
Pids = maps:fold(CreateMultipleThreads, [], Map),
Pids.

Obviously, I can't actually test this, because calculator:init_method/3 doesn't exist for me, but you get the idea, hopefully.

Upvotes: 2

Related Questions