Why receive expression is sometimes called selective receive?
What is the "save queue"?
How the after section works?
There is a special "save queue" involved in the procedure that when you first encounter the receive expression you may ignore its presence.
Optionally, there may be an after-section in the expression that complicates the procedure a little.
The receive expression is best explained with a flowchart:
receive
pattern1 -> expressions1;
pattern2 -> expressions2;
pattern3 -> expressions3
after
Time -> expressionsTimeout
end
Why receive expression is sometimes called selective receive?
-module(my).
%-export([test/0, myand/2]).
-compile(export_all).
-include_lib("eunit/include/eunit.hrl").
start() ->
spawn(my, go, []).
go() ->
receive
{xyz, X} ->
io:format("I received X=~w~n", [X])
end.
In the erlang shell:
1> c(my).
my.erl:3: Warning: export_all flag enabled - all functions will be exported
{ok,my}
2> Pid = my:start().
<0.79.0>
3> Pid ! {hello, world}.
{hello,world}
4> Pid ! {xyz, 10}.
I received X=10
{xyz,10}
Note how there was no output for the first message that was sent, but there was output for the second message that was sent. The receive was selective: it did not receive all messages, it received only messages matching the specified pattern.
What is the "save queue"?
-module(my).
%-export([test/0, myand/2]).
-compile(export_all).
-include_lib("eunit/include/eunit.hrl").
start() ->
spawn(my, go, []).
go() ->
receive
{xyz, X} ->
io:format("I received X=~w~n", [X])
end,
io:format("What happened to the message that didn't match?"),
receive
Any ->
io:format("It was saved rather than discarded.~n"),
io:format("Here it is: ~w~n", [Any])
end.
In the erlang shell:
1> c(my).
my.erl:3: Warning: export_all flag enabled - all functions will be exported
{ok,my}
2> Pid = my:start().
<0.79.0>
3> Pid ! {hello, world}.
{hello,world}
4> Pid ! {xyz, 10}.
I received X=10
What happened to the message that didn't match?{xyz,10}
It was saved rather than discarded.
Here it is: {hello,world}
How the after section works?
-module(my).
%-export([test/0, myand/2]).
-compile(export_all).
-include_lib("eunit/include/eunit.hrl").
start() ->
spawn(my, go, []).
go() ->
receive
{xyz, X} ->
io:format("I received X=~w~n", [X])
after 10000 ->
io:format("I'm not going to wait all day for a match. Bye.")
end.
In the erlang shell:
1> c(my).
my.erl:3: Warning: export_all flag enabled - all functions will be exported
{ok,my}
2> Pid = my:start().
<0.79.0>
3> Pid ! {hello, world}.
{hello,world}
I'm not going to wait all day. Bye.4>
Another example:
-module(my).
%-export([test/0, myand/2]).
-compile(export_all).
-include_lib("eunit/include/eunit.hrl").
sleep(X) ->
receive
after X * 1000 ->
io:format("I just slept for ~w seconds.~n", [X])
end.
In the erlang shell:
1> c(my).
my.erl:3: Warning: export_all flag enabled - all functions will be exported
{ok,my}
2> my:sleep(5).
I just slept for 5 seconds.
ok
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]
I created a new file, based on OTP gen_server behaviour.
This is the begining of it:
-module(appender_server).
-behaviour(gen_server).
-export([start_link/1, stop/0]).
-export([init/1, handle_call/3, handle_cast/2]).
start_link(filePath) ->
gen_server:start_link({local, ?MODULE}, ?MODULE, filePath, []).
init(filePath) ->
{ok, theFile} = file:open(filePath, [append]). % File is created if it does not exist.
...
The file compiled ok using c(appender_server).
When I try to call start_link function from the shell, like this:
appender_server:start_link("c:/temp/file.txt").
I get:
** exception error: no function clause matching appender_server:start_link("c:/temp/file.txt") (appender_server.erl,
line 10)
What do I do wrong?
filePath is an atom--not a variable:
7> is_atom(filePath).
true
In erlang, variables start with a capital letter. The only way erlang could match your function clause would be to call the function like this:
appender_server:start_link(filePath)
Here is an example:
-module(a).
-compile(export_all).
go(x) -> io:format("Got the atom: x~n");
go(y) -> io:format("Got the atom: y~n");
go(X) -> io:format("Got: ~w~n", [X]).
In the shell:
3> c(a).
a.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,a}
4> a:go(y).
Got the atom: y
ok
5> a:go(x).
Got the atom: x
ok
6> a:go(filePath).
Got: filePath
ok
7> a:go([1, 2, 3]).
Got: [1,2,3]
ok
8>
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 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