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.
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.
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
Related
I am trying to start a simple process that will loop and receive addition or subtraction commands to calculate them. However when I register my process I try to print it with a whereis() to see if it is up and running and it returns undefined. Any idea what is going wrong?
-module(math).
-export([start/0, math/0]).
start() -> register(myprocess, spawn(math, math(), [])).
math() ->
io:format("~p~n", [whereis(myprocess)]),
receive
{add, X, Y} ->
io:format("~p + ~p = ~p~n", [X,Y,X+Y]),
math();
{sub, X, Y} ->
io:format("~p - ~p = ~p~n", [X,Y,X-Y]),
math()
end.
Here is my input in the erl shell as well:
Eshell V12.0 (abort with ^G)
1> c(math).
{ok,math}
2> math:start().
undefined
Remove the parens on the math() parameter passed to spawn.
The second parameter to spawn is supposed to be the atom for the name of the process, but you're actually invoking the function and passing the result to spawn (all of which has to happen before register itself is called).
I am new to Erlang and trying to pass the result obtained from one function to another through message passing but I am unsure why it is giving me badarg errors when I do ie main ! {numbers, 1, 100}. I have tried to make some changes, as seen in the greyed out portions, but the message didn't get passed when using From. Here is my code:
-module(numbers).
-export([start_main/0,main/2,proc/0,sumNumbers/2]).
main(Total, N) ->
if
N == 0 ->
io:format("Total: ~p ~n", [Total]);
true ->
true
end,
receive
{numbers, Low, High} ->
Half = round(High/2),
Pid1 = spawn(numbers, proc, []),
Pid2 = spawn(numbers, proc, []),
Pid1 ! {work, Low, Half},
Pid2 ! {work, Half+1, High};
%% Pid1 ! {work, self(), Low, Half},
%% Pid2 ! {work, self(), Half+1, High},
{return, Result} ->
io:format("Received ~p ~n", [Result]),
main(Total+Result, N-1)
end.
proc() ->
receive
{work, Low, High} ->
io:format("Processing ~p to ~p ~n", [Low, High]),
Res = sumNumbers(Low,High),
main ! {return, Res},
proc()
%% {work, From, Low, High} ->
%% io:format("Processing ~p to ~p ~n", [Low, High]),
%% Res = sumNumbers(Low,High),
%% From ! {return, Res},
%% proc()
end.
sumNumbers(Low, High) ->
Lst = lists:seq(Low,High),
lists:sum(Lst).
start_main() ->
register(main, spawn(numbers, main, [0,2])).
If you get a badarg from main ! Message, it means that there is no process registered under the name main. It either didn't get started or properly registered to begin with, or it has died at some point. You can add some more print statements to follow what happens.
You can use erlang:registered/2 to see what is registered.
When you send the first message to the main, it is handled by the receive statement with the message {numbers,1,100}, in this statement you spawn twice the proc() function, and terminate the receive statement.
Thus, the main process dies, it is no more registered, and as soon as the proc functions try to send their message at line main ! {return, Res}, you get the badarg error.
You need to recursively call the main function as you do it at line main(Total+Result, N-1) to keep the main process alive. (see RichardC answer)
Executing this function:
start_main() ->
register(main, spawn(numbers, main, [0,2])).
will start a process called main, which executes the function numbers:main/2. After the function numbers:main/2 starts executing, it enters a receive clause and waits for a message.
If you then execute the function proc/0, it too will enter a receive clause and wait for a message. If you send the process running proc/0 a message, like {work, 1, 3}, then proc/0 will send a message, like {return, 6}, to numbers:main/2; and numbers:main/2 will display some output. Here's the proof:
~/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(numbers).
{ok,numbers}
2> numbers:start_main().
true
3> Pid = spawn(numbers, proc, []).
<0.73.0>
4> Pid ! {work, 1, 3}.
Processing 1 to 3
{work,1,3}
Received 6
5>
As you can see, there's no badarg error. When you claim something happens, you need to back it up with proof--merely saying that something happens is not enough.
I do not know what overload of spawn to use when launching a process from the erlang shell , since i need to pass arguments.
A=spawn(
fun(TID)->
receive {FROM,MSG}->
FROM ! {self(),MSG}
after 0 ->
TID !{self(),timeouted}
end
end,
TID
).
There is no overload for just the function and arguments.
What is the module name when launching from shell ?
I have also tried:
A=spawn(?MODULE,fun()->....,TID).
P.S
In my case as you can see i need to provide arguments to the spawn method , while running it directly from the erlang shell.
Just embed the definition in a fun:
A = fun(X) ->
TID = X,
spawn(
fun()->
receive {FROM,MSG}->
FROM ! {self(),MSG}
after 0 ->
TID !{self(),timeouted}
end
end
)
end.
and then you can use A(YourParam).
Typically, you define a function in a module:
-module(a).
-compile(export_all).
go(X)->
receive {From, Msg}->
From ! {self(), Msg}
after 0 ->
io:format("~s~n", [X])
end.
Then do this:
9> c(a).
a.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,a}
10> Pid = spawn(a, go, ["hello"]).
hello
<0.95.0>
Defining functions in the shell is too much of a pain in the ass.
Response to comment:
Here's how you can do simple testing in erlang:
-module(a).
-compile(export_all).
-include_lib("eunit/include/eunit.hrl").
do(Y) ->
Y.
go(X)->
receive {From, Msg}->
From ! {self(), Msg}
after 0 ->
X
end.
do_test() ->
10 = do(10).
go_test() ->
"hello" = go("hello").
In the shell:
1> c(a).
2> a:test().
2 tests passed.
ok
Here's what happens when a test fails:
5> a:test().
a: go_test...*failed*
in function a:go_test/0 (a.erl, line 18)
**error:{badmatch,"hello"}
output:<<"">>
=======================================================
Failed: 1. Skipped: 0. Passed: 1.
error
6>
You don't even need to use eunit because you can simply do:
go_test() ->
"hello" = go("hello").
Then in the shell:
1> c(a).
a.erl:2: Warning: export_all flag enabled - all functions will be exported
2> a:go_test().
You'll get a bad match error if go("hello") doesn't return "hello":
** exception error: no match of right hand side value "hello"
in function a:go_test/0 (a.erl, line 18)
The advantage of using eunit is that with one command, a:test(), you can execute all the functions in the module that end in _test.
I am not entirely understanding how records work with Mnesia, and what is the effect of changing record types. Here is in example:
Erlang/OTP 17 [erts-6.2] [source] [64-bit] [async-threads:10] [kernel-poll:false]
Eshell V6.2 (abort with ^G)
1> c(test).
{ok,test}
2> mnesia:start().
ok
3> test:reset_db().
{atomic,ok}
4> test:add_sensor("1a0",12,erlang:now()).
{atomic,ok}
5> test:add_sensor("1a1",10,erlang:now()).
{atomic,ok}
6> test:list_sensors().
[{sensors,"1a0",12,{1484,392274,122051}},
{sensors,"1a1",10,{1484,392280,673175}}]
7> test:list_sensors_id().
["1a0","1a1"]
So this all makes sense - we created a table (test:reset_db) with records of type "sensors", and added two sensors (test:add_sensor). We see both records of "sensors" type. Now lets modify the table:
8> test:update_db().
{atomic,ok}
9> test:list_sensors().
[{sensors_new,"1a0",12,{1484,392274,122051},0},
{sensors_new,"1a1",10,{1484,392280,673175},0}]
10> test:list_sensors_id().
["1a0","1a1"]
11> q().
ok
So this is the part I don't get - we updated our table (test:update_db) so now we have "sensors" tables with "sensors_new" record types - this is consistent with what we see on test:list_sensors, but what I don't get is why test:list_sensors_id() still works? Is there a mapping between #sensors_new.name and #sensors.id? How Erlang/Mnesia knows that "X#sensors.id" and "X#sensors_new.name" are the same field after translation? Or what am I missing?
-include_lib("stdlib/include/qlc.hrl").
-module(test).
-compile(export_all).
-record(sensors,{id,val,update}).
-record(sensors_new,{name,val,update,type}).
reset_db() ->
mnesia:delete_table(sensors),
mnesia:create_table(sensors, [{attributes, record_info(fields, sensors)}]).
update_db() ->
Transformer = fun(X) when is_record(X, sensors) ->
#sensors_new{name = X#sensors.id,
val = X#sensors.val,
update = X#sensors.update,
type = 0} end,
{atomic, ok} = mnesia:transform_table(sensors,Transformer,record_info(fields, sensors_new),sensors_new).
add_sensor(Id, Val, Update) ->
Row = #sensors{id=Id, val=Val, update=Update},
F = fun() ->
mnesia:write(Row)
end,
mnesia:transaction(F).
list_sensors() ->
do(qlc:q([X || X <-mnesia:table(sensors)])).
list_sensors_id() ->
do(qlc:q([X#sensors.id || X <-mnesia:table(sensors)])).
do(Q) ->
F = fun() -> qlc:e(Q) end,
{atomic, Val} = mnesia:transaction(F),
Val.
Quick review first: Records in Erlang are just syntactic sugar over tuples with the record name added as the first element. When you access the Nth field in a record R, Erlang is actually converting that to use element(N+1, R). In this example, #sensors.id and #sensors_new.name both give the same value of 2, so accessing either of those is just element(2, R).
Now by default, accessing the fields of a record through the wrong type should fail (barring something like two records having the same name). If a variable Foo is bound to a record of the type #sensors, but you try to access something through #sensors_new, like say Foo#sensors_new.name, that will normally throw a badrecord error, like this:
4> Foo = #sensors{id="bar"}.
#sensors{id = "bar"}
5> Foo#sensors_new.name.
** exception error: {badrecord,sensors_new}
However, it seems that check is bypassed when using QLCs (the QLC parse transform passes in no_strict_record_tests, disabling that "strict" record field access test). If I had to guess, I'd say this was an optimization combined with an assumption that you wouldn't use the same QLC if you swapped the backing record.
I am trying to inspect the messages a node receives from other nodes, but in some other manner other than flush(), because the message size is rather big and it doesn't help. Also, I can see the messages with erlang:process_info(self(), messages_queue_len)., but I would like some way of extracting one message at a time in some kind of variable for debugging purposes.
You might want to have a look to the dbg module in Erlang.
Start the tracer:
dbg:tracer().
Trace all messages received (r) by a process (in this case self()):
dbg:p(self(), r).
More information here.
or you can use:
1> F = fun() -> receive X -> {message, X} after 0 -> no_message end end.
#Fun<erl_eval.20.111823515>
2> F().
no_message
3> self() ! foo.
foo
4> self() ! bar.
bar
5> F().
{message, foo}
6> F().
{message, bar}
... to prevent blocking
receive is the erlang primitive for taking messages from the mailbox.
See: http://www.erlang.org/doc/getting_started/conc_prog.html#id2263965
If you just want to get the first message in the shell for debugging, you could try defining a fun like this:
1> self() ! foo.
foo
2> F = fun() -> receive X -> X end end.
#Fun<erl_eval.20.67289768>
3> F().
foo