I'm a beginner at Erlang and I've been working through "Learn You Some Erlang For Great Good!". I use a modified version of this example code where the critic has a parameter:
critic(Count) ->
receive
{From, {"Rage Against the Turing Machine", "Unit Testify"}} ->
From ! {self(), {"They are great!", Count}};
{From, {"System of a Downtime", "Memoize"}} ->
From ! {self(), {"They're not Johnny Crash but they're good.", Count}};
{From, {"Johnny Crash", "The Token Ring of Fire"}} ->
From ! {self(), {"Simply incredible.", Count}};
{From, {_Band, _Album}} ->
From ! {self(), {"They are terrible!", Count}}
end,
critic(Count).
Which is spawned like this:
restarter() ->
process_flag(trap_exit, true),
Pid = spawn_link(?MODULE, critic, [my_atom]),
register(critic, Pid),
receive
{'EXIT', Pid, normal} -> % not a crash
ok;
{'EXIT', Pid, shutdown} -> % manual termination, not a crash
ok;
{'EXIT', Pid, _} ->
restarter()
end.
The module is used like this:
1> c(linkmon).
{ok,linkmon}
2> Monitor = linkmon:start_critic().
<0.163.0>
3> linkmon:judge("Rage Against the Turing Machine", "Unit Testify").
{"They are great!",my_atom}
Now, when I change "my_atom" to a simple number (like 255) the monitor crashes:
1> c(linkmon).
{ok,linkmon}
2> Monitor = linkmon:start_critic().
=ERROR REPORT==== 14-Jul-2013::20:42:20 ===
Error in process <0.173.0> with exit value: {badarg,[{erlang,register,[critic,<0.174.0>] []},{linkmon,restarter,0,[{file,"linkmon.erl"},{line,16}]}]}
However, it does work when I send [1] (so the code is "spawn(....., [[255]]).")
Why can't I pass a single number? Is just skimming over the documentation of spawn/3 doesn't really tell me anything... except maybe that I missed something and a number is not an Erlang term. But then how do I pass a number?
The error message says that the call to register(critic, Pid) on line 16 crashes due to "badarg" even though the arguments look ok. This can happen if the process referred to by Pid is already dead (if it crashes immediately, e.g. if you pass the wrong number of args), or if you already have a process around using that name. Ensure that the length of the list in the spawn(Mod,Fun,[...]) matches the number of args to your critic() function, and call "whereis(critic)" in the shell to check if there's an old process blocking the name from being reused.
Related
I want to spawn 1000 or a variable number of processes in Erlang.
server.erl:
-module(server).
-export([start/2]).
start(LeadingZeroes, InputString) ->
% io:format("Leading Zeroes: ~w", [LeadingZeroes]),
% io:format("InputString: ~p", [InputString]).
mineCoins(LeadingZeroes, InputString, 100).
mineCoins(LeadingZeroes, InputString, Target) ->
PID = spawn(miner, findTargetHash(), []), % How to spawn this process 1000 times so that each process computes something and sends the results here
PID ! {self(), {mine, LeadingZeroes, InputString, Target}},
receive
{found, Number} ->
io:fwrite("Rectangle area: ~w", [Number]);
% {square, Area} ->
% io:fwrite("Square area: ~w", [Area]);
Other ->
io:fwrite("In Other!")
end.
% io:fwrite("Yolo: ~w", [Square_Area]).
miner.erl (client):
-module(miner).
-export([findTargetHash/0]).
findTargetHash() ->
receive
{From , {mine, LeadingZeroes, InputString, Target}} ->
% do something here
From ! {found, Number};
{From, {else, X}} ->
io:fwrite("In Else area"),
From ! {square, X*X}
end,
findTargetHash().
Here, I wish to spawn the processes, 1000 of them(miner), how does one achieve this? Through list comprehensions or recursion or any other way?
Generally, you can do something N times like this:
-module(a).
-compile(export_all).
go(0) ->
io:format("!finished!~n");
go(N) ->
io:format("Doing something: ~w~n", [N]),
go(N-1).
In the shell:
3> c(a).
a.erl:2:2: Warning: export_all flag enabled - all functions will be exported
% 2| -compile(export_all).
% | ^
{ok,a}
4> a:go(3).
Doing something: 3
Doing something: 2
Doing something: 1
!finished!
ok
If you need to start N processes and subsequently send messages to them, then you will need their pids to do that, so you will have to save their pids somewhere:
go(0, Pids) ->
io:format("All workers have been started.~n"),
Pids;
go(N, Pids) ->
Pid = spawn(b, worker, [self()]),
go(N-1, [Pid|Pids]).
-module(b).
-compile(export_all).
worker(From) ->
receive
{From, Data} ->
io:format("Worker ~w received ~w.~n", [self(), Data]),
From ! {self(), Data * 3};
Other ->
io:format("Error, received ~w.~n", [Other])
end.
To start N=3 worker processes, you would call go/2 like this:
Pids = a:go(3, []).
That's a little bit awkward for someone who didn't write the code: why do I have to pass an empty list? So, you could define a go/1 like this:
go(N) -> go(N, []).
Then, you can start 3 worker processes by simply writing:
Pids = go(3).
Next, you need to send each of the worker processes a message containing the work they need to do:
do_work([Pid|Pids], [Data|Datum]) ->
Pid ! {self(), Data},
do_work(Pids, Datum);
do_work([], []) ->
io:format("All workers have been sent their work.~n").
Finally, you need to gather the results from the workers:
gather_results([Worker|Workers], Results) ->
receive
{Worker, Result} ->
gather_results(Workers, [Result|Results])
end;
gather_results([], Results) ->
Results.
A couple of things to note about gather_results/2:
The Worker variable in the receive has already been assigned a value in the head of the function, so the receive is not waiting for just any worker process to send a message, rather the receive is waiting for a particular worker process to send a message.
The first Worker process in the list of Workers may be the longest running process, and you may wait in the receive for, say, 10 minutes for that process to finish, but then getting the results from the other worker processes will require no waiting. Therefore, gathering all the results will essentially take as long as the longest process plus a few microseconds to loop through the other processes. Similarly, for other orderings of the longest and shortest processes in the list, it will only take a time equal to the longest process plus a few microseconds to receive all the results.
Here is a test run in the shell:
27> c(a).
a.erl:2:2: Warning: export_all flag enabled - all functions will be exported
% 2| -compile(export_all).
% | ^
{ok,a}
28> c(b).
b.erl:2:2: Warning: export_all flag enabled - all functions will be exported
% 2| -compile(export_all).
% | ^
{ok,b}
29> Pids = a:go(3, []).
All workers have been started.
[<0.176.0>,<0.175.0>,<0.174.0>]
30> a:do_work(Pids, [1, 2, 3]).
All workers have been sent their work.
Worker <0.176.0> received 1.
Worker <0.175.0> received 2.
Worker <0.174.0> received 3.
ok
31> a:gather_results(Pids, []).
[9,6,3]
experimenting with distributed erlang, here's what I have:
loop()->
receive {From, ping} ->
io:format("received ping from ~p~n", [From]),
From ! pong,
loop();
{From, Fun} when is_function(Fun) ->
io:format("executing function ~p received from ~p~n", [Fun, From]),
From ! Fun(),
loop()
end.
test_remote_node_can_execute_sent_clojure()->
Pid = spawn(trecias, fun([])-> loop() end),
Pid ! {self(), fun()-> erlang:nodes() end},
receive Result ->
Result = [node()]
after 300 ->
timeout
end.
getting: Can not start erlang:apply,[#Fun<tests.1.123107452>,[]] on trecias
node I execute the test on runs on the same machine as the node 'trecias'. Both nodes can load same code.
Any ideas what is amiss?
In the spawn call, you've specified the node name as trecias, but you need to specify the full node name including the hostname, e.g. trecias#localhost.
Also, the function you pass to spawn/2 must take zero arguments, but the one in the code above takes one argument (and crashes if that argument isn't the empty list). Write it as fun() -> loop() end instead.
When spawning an anonymous function on a remote node, you also need to make sure that the module is loaded on both nodes, with the same version. Otherwise you'll get a badfun error.
I want to write program which creates 2 processes.
First print number , send it to second process and so on.
However I have problem in start function.
-module(zad).
-export([start/0, one/0, two/0]).
one() ->
receive
{go1, N} ->
io:format("1 ~w~n", [N]),
two ! {go2, N+1},
one();
{go2, 50} ->
io:format("END ~w~n", [N+1]),
two ! finished
end.
two() ->
receive
finished ->
io:format("two finished~n", []);
{go2, N} ->
io:format("2 ~w~n", [N]),
one ! {go1, N+1 },
two()
end.
start() ->
register(two, spawn(zad, two, [])),
register(one, spawn(zad, one, [])),
one ! {go1, 0}.
here's error
** exception error: bad argument
in function register/2
called as register(two,<0.146.0>)
in call from zad:start/0 (zad.erl, line 29)
Does it mean that I cant register 2 processes in start? What is wrong with this code?
UPDATE
It is really weird. but after I changed
{go2, 50} -> io:format("END ~w~n", [N+1]),
to
{go2, 50} -> io:format("END ~w~n", [50]),
error disappeared.
It's really strange because problem is in one(), but error was in register(two)
You can register two processes in start/0. It means the values you are passing into register/2 are wrong. From the documentation(http://erlang.org/doc/man/erlang.html#register-2):
Failures:
badarg If PidOrPort is not an existing local process or port.
badarg If RegName is already in use.
badarg If the process or port is already registered (already has a name). badarg If RegName is the atom undefined.
Likely what has happened is the process died before register/2 was called (see the first failure in the list above).
Following is the program in which i have tried to spawn 3 processes form a method called best. I want to receive response from all the processes and store them in a tuple but I am able to get only one response.
test() ->
receive
{From,N} -> From!{self(),N},
loop()
end.
best(N) ->
Aid=spawn(fun t:loop/0),
Aid ! {self(),N},
Bid=spawn(fun t:loop/0),
Bid ! {self(),N},
Cid=spawn(fun t:loop/0),
Cid ! {self(),N},
receive
{Pid,Response} ->{Response}
end.
Can someone please help me out with this probem
Your receive bloc, in the best/2 function exit as soon as it receives one message. If you launch this code in the shell, you can verify that the other message are still in the message queue with the function flush(). (The code you posted is missing the t:loop/0 function, I guess it will compute something based on N and return the answer via a message to the spawner)
To be able to receive more than one message, you must put the receive bloc in a "loop" that recursively calls itself until it got all answers. You will have to use a variable that allows the recursive loop to know when it is finished (number of answers expected, list of processes that should answer...) and collect the answers in a list variable for example.
-module(wy).
-compile(export_all).
loop() ->
Self = self(),
receive
{From, Ref, N} ->
From ! {Self, Ref, N * N}
end.
receive_result(Ref) ->
receive
{Pid, Ref, R} ->
io:format("process ~p: ~p~n", [Pid, R]),
receive_result(Ref)
after 10 ->
ok
end.
best() ->
APid = spawn(fun loop/0),
BPid = spawn(fun loop/0),
CPid = spawn(fun loop/0),
Self = self(),
Ref = make_ref(),
APid ! {Self, Ref, 2},
BPid ! {Self, Ref, 3},
CPid ! {Self, Ref, 4},
receive_result(Ref).
You can follow this small code. The result is:
9> wy:best().
process <0.77.0>: 4
process <0.78.0>: 9
process <0.79.0>: 16
ok
From the Learn You Some Erlang for Great Good!
Another special case is when the timeout is at 0:
flush() ->
receive
_ -> flush()
after 0 ->
ok
end
.
When that happens, the Erlang VM will try and find a message that fits
one of the available patterns. In the case above, anything matches. As
long as there are messages, the flush/0 function will recursively call
itself until the mailbox is empty. Once this is done, the after 0 ->
ok part of the code is executed and the function returns.
I don't understand purpose of after 0. After reading above text I thought it was like after infinity (waiting forever) but I changed a little the flush function:
flush2() ->
receive
_ -> timer:sleep(1000), io:format("aa~n"), flush()
after 0 ->
okss
end
.
flush3() ->
receive
_ -> io:format("aa~n"), flush()
after 0 ->
okss
end
.
In the first function it waits 1 second and in the second function it doesn't wait.
In both cases it doesn't display a text (aa~n).
So it doesn't work as after infinity.
If block between the receive and the after are not executed then above 2 codes can be simplified to:
flush4() ->
okss
.
What I am missing?
ps. I am on the Erlang R16B03-1, and author of the book was, as fair I remember, was on the Erlang R13.
Every process has a 'mailbox' -- message queue. Messages can be fetched by receive. if there is no messages in the queue. after part specifies how much time 'receive will wait for them. So after 0 -- means process checking (by receive ) if any messages in the queue and if queue is empty immediately continue to next instructions.
It can be used for instance if we want periodically check if any messages here and to do something (hopefully helpful) if there is no messages.
Consider after 0 to be finally.
Consider the use of after 0 to process receives with a priority: http://learnyousomeerlang.com/more-on-multiprocessing#selective-receives
May this different look on things enlighten you.
You can play with the following shell command to understand the effect of the after command:
4> L = fun(G) ->
4> receive
4> stop -> ok;
4> M -> io:format("received ~p~n",[M]), G(G)
4> after 0 ->
4> io:format("no message~n")
4> end
4> end.
#Fun<erl_eval.6.80484245>
5> F = fun() -> timer:sleep(10000),
5> io:format("end of wait for messages, go to receive block~n"),
5> L(L)end.
#Fun<erl_eval.20.80484245>
6> spawn(F).
<0.46.0>
end of wait for messages, go to receive block
no message
7> P1 = spawn(F).
<0.52.0>
8> P1 ! hello.
hello
end of wait for messages, go to receive block
received hello
no message
9> P2 ! hello, P2 ! stop.
* 1: variable 'P2' is unbound
8> P2 = spawn(F).
<0.56.0>
9> P2 ! hello, P2 ! stop.
stop
end of wait for messages, go to receive block
received hello
10>
If you do not intend to use a nested receive, rather than using "after" part, I think a better approach is to use "Unexpected ->" variable to handle all unmatched messages.