I just had a simple question and I can't seem to find an answer to it. Basically my question is if I have a function recording state (recursive) and I send multiple messages to it, will it keep going through the receive block until it no longer has messages in its "mailbox"?
state(Fridge) ->
receive
Pat1 ->
io:format("ok"),
state(S);
Pat2 ->
io:format("not ok"),
state(S)
end.
So if I'd send to this process 3 messages (Pat1, Pat2, Pat1) using "!" and its not able to go into its loop before receiving messages will it still print out the following?
1> "ok"
2> "not ok"
3> "ok"
Sorry if this isn't very clearly put, by simplifying the question it might make it hard to picture what I am asking.
Your question isn't clear but you seem to be asking whether the process will receive the three messages even if they're sent before the target process has called receive — if that's the question, the answer is yes. When you send a message to a process, it goes into that process's message queue until the process calls receive to remove it from the message queue and deal with it.
If you call erlang:process_info(Pid, messages) where Pid is the receiver's process id, you can see what messages are in its queue. You might try this from the Erlang shell.
As an extreme example of message queueing, under some heavy load conditions it can be a source of out-of-memory problems if a receiver can't keep up with a fast sender. Under these conditions, a receiver's message queue might grow without bound until the system runs out of memory.
Does this answer your question?
1> OUT = fun(X) -> io:format(">>> ~p~n", [X]) end.
#Fun<erl_eval.6.54118792>
2> F = fun X() -> receive foo -> OUT(foo), X(); bar -> OUT(bar), X() end end.
#Fun<erl_eval.44.54118792>
3> P = spawn(F).
<0.38.0>
4> [ P ! X || X <- [foo, bar, foo]].
>>> foo
[foo,bar,foo]
>>> bar
>>> foo
A message arrives in the mailbox and then receive patterns are applied to the message like the function clause or case statement. But unlike those, if none of them match, next message is processed and the previous one left in the message box untouched. Other receive clause starts always from beginning of message queue.
1> OUT = fun(X) -> io:format(">>> ~p~n", [X]) end.
#Fun<erl_eval.6.54118792>
2> F = fun() -> receive start -> (fun X() -> receive foo -> OUT(foo), X(); bar -> OUT(bar), X() end end)() end end.
#Fun<erl_eval.20.54118792>
3> P = spawn(F).
<0.38.0>
4> [ P ! X || X <- [foo, bar, foo]].
[foo,bar,foo]
5> P! start.
>>> foo
start
>>> bar
>>> foo
Note that foo, bar, foo is in the queue in the first receive but it is not processed. When start arrives (last in the queue) second receive starts process foo and bar messages.
-module(wy).
-compile(export_all).
state() ->
timer:sleep(2000),
io:format("~p~n", [erlang:process_info(self(), messages)]),
receive
pat1 ->
io:format("ok~n"),
state();
pat2 ->
io:format("not ok~n"),
state()
end.
main() ->
Pid = spawn(fun state/0),
[ Pid ! X || X <- [pat1, pat2, pat1]].
You can run this code, from the output you can understand everything.
**Note:**when you send message to a process, the sent messages will be stored in mail box of the process.
6> wy:main().
[pat1,pat2,pat1]
7> {messages,[pat1,pat2,pat1]}
7> ok
7> {messages,[pat2,pat1]}
7> not ok
7> {messages,[pat1]}
7> ok
7> {messages,[]}
7>
One comments for your code:
receive
Pat1 ->
io:format("ok"),
state(S);
Pat2 ->
io:format("not ok"),
state(S)
end.
the second clause will not match forever.
Related
I'm trying to do something like this:
test(Tester) ->
case Tester of
start -> X = 4
ok -> X = X + 5,
Y = X/5;
terminate -> Y
end.
But not exactly this. I Know it can be achieved with tail or simple recursion.
normally X and Y are unbound.
Is there any way to communicate between these cases without the usage of erlang global variables?
Erlang is a functional language it means we don't communicate between different parts of the code or store values in variables without purpose, we just compute to return value (and sometimes make some sideeffect). If we have common computation in different branches of code we can simply place it in common function.
test(Tester) ->
case Tester of
start -> 4;
ok -> computeY();
terminate -> computeY()
end.
computeY() ->
X = 4 + 5,
X/5.
If you need to access a variable in any clause body of a case statement, You have to assign it before case statement or sometimes you can assign it in case clause pattern:
test(Arg) ->
Size = get_size(Arg), % I will use 'Size' in each clause body
case Arg of
#{foo := Foo} -> % if Arg is an Erlang map and has key 'foo'
% I can use 'Foo' only here:
io:format("It's a map with size ~p and has key foo with value ~p\n", [Size, Foo]);
[Baz|_] -> % if Arg is an Erlang list with at least one element
% I can use 'Baz' only here and for example i can NOT use 'Foo' here:
io:format("It's a list with size ~p and its first element is ~p\n", [Size, Baz]);
_ ->
io:format("Unwanted argument ~p with ~p size\n", [Arg, Size])
end.
get_size(X) when is_map(X) -> map_size(X);
get_size(X) when is_list(X) -> length(X);
get_size(_) -> unknown.
I put above code in an Erlang fun named Test to using it in shell without need to compile a module file:
1> Test([5,4,3,2,1]).
It's a list with size 5 and its first element is 5
ok
2> Test(#{key => value, foo => ':)'}).
It's a map with size 2 and has key foo with value ':)'
ok
3> Test([]).
Unwanted argument [] with 0 size
ok
4> Test(#{key => value}).
Unwanted argument #{key => value} with 1 size
ok
5> Test(13).
Unwanted argument 13 with unknown size
ok
If you are curious about variable binding in case, I recommend to read this article
To do this in Erlang you would start (spawn) a process that would hold X in memory as well as the PID (process id) of the process it is supposed to reply to unless you want to pass it a different PID every time along with start/ok/terminate. Processes in Erlang have their own memory, state or loopData. After you spawn a process that knows how to handle specific messages, you pass it the messages and it replies by sending a message back.
start_test() ->
TestPID = spawn(?MODULE, test, [self()]),
TestPID ! start,
receive
X -> io:format("X is: ~p~n",[X]
end,
TestPID ! ok,
receive
{X,Y} -> io:format("X is: ~p, Y is: ~p~n",[X, Y]
end,
TestPID ! terminate,
receive
Y -> io:format("Y is: ~p~n",[Y]
end.
test(PID) ->
receive
start -> PID ! 4,
test(4, undefined, PID);
terminate -> undefined
end.
test(X, Y, PID) ->
receive
ok -> PID ! {X+5, (X+5)/5},
test(X+5, (X+5)/5, PID);
terminate -> PID ! Y
end.
Don't forget to create a module and export start_test/0 and test/1
If you run start_test() you should get an output of
X is: 4
X is: 9, Y is: 1.8
Y is: 1.8
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.
I have a variable:
Data = [[<<>>,
[<<"10">>,<<"171">>],
[<<"112">>,<<"Gen20267">>],
[<<"52">>,<<"20100812-06:32:30.687">>]]
I am trying to pattern match for two specific cases..
One where anything that resembles the outside structure - simply []
Anything inside goes I have tried [ _ ] but no go?
The Second, for a specific pattern inside, like when I see a <<"10">> or <<"112">> or <<"52">> then I am going to take the right side which is the actual data into an atom.
Basically the <<"10">> or <<"112">> or <<"52">> are the fields, the right side the data.
I have tried statements like [<<"10">>, _ ] still no go
Here is the rest of the code:
dataReceived(Message) ->
receive
{start} ->
ok;
[ _ ] -> %%No go
io:format("Reply 1 = ~p~n", [Message]);
[<<"10">>, _ ] -> %%No go
io:format("Reply 1 = ~p~n", [Message])
end.
As a note the Message is not sent as a tuple it is exactly like Data =
Can anyone lead me in the right direction?
Thanks and Goodnight!
-B
UPDATE
Ok now I think Im getting warmer, I have to pattern match whatever comes in.
So if I had say
Message = = [[<<>>],
[<<"10">>,<<"171">>],
[<<"112">>,<<"Gen20267">>],
[<<"52">>,<<"20100812-06:32:30.687">>]]
And I was looking to pattern match the field <<"112">>
Such as the 112 is always going to say 112, but the Gen2067 can change whenever to whatever.. its the data, it will be stored in a variable.
loop() ->
receive
[_,[<<"112">>, Data], _] when is_list(X) -> %% Match a list inside another.
?DEBUG("Got a list ~p~n", [X]),
loop();
_Other ->
?DEBUG("I don't understand ~p~n", [_Other]),
loop()
end.
I feel im close, but not 100%
-B
Update OP is trying to pass an argument to the function and not send messages.
As the name indicates the receive block is used to receive and process messages sent to a process. When you call dataReceived with an argument it proceeds to wait for messages. As no messages are sent it will continue to wait endlessly. Given the current code if you want it to do something then you'll have to spawn the function, get the process ID and then send a message to the process ID.
You probably need a function where the argument is pattern matched and not messages.
Something like this:
dataReceived([Message]) when is_list(Message) ->
io:format("Got a list as arg ~p~n", [Message]);
dataReceived(_Other) ->
io:format("Unknown arg ~p~n", [_Other]).
On a side note your third pattern [X] when is_list(X) will never match as the second pattern is a superset of the third. Anything that matches [X] when is_list(X) will always match [X] and therefore your third match clause will never get triggered.
Original Answer
I am not sure I understand your question. Are you trying to send a message to the function or are you passing it an argument?
This is a partial answer about how to match a list of lists in case you are sending a message.
-module(mtest).
-export([run/0]).
-ifdef(debug).
-define(DEBUG(Format, Args), io:format(Format, Args)).
-else.
-define(DEBUG(Format, Args), void).
-endif.
loop() ->
receive
[X] when is_list(X) -> %% Match a list inside another.
?DEBUG("Got a list ~p~n", [X]),
loop();
_Other ->
?DEBUG("I don't understand ~p~n", [_Other]),
loop()
end.
Take a look at the first clause in the receive block. [X] when is_list(X) will bind the inner list to the name X. I tested it with the value of Data you provided and it worked.
%% From the shell.
1> c(mtest, {d, debug}).
{ok,mtest}
2> Pid = mtest:run().
<0.40.0>
3> Data = [[<<>>, [<<"10">>,<<"171">>], [<<"112">>,<<"Gen20267">>], [<<"52">>,<<"20100812-06:32:30.687">>]]].
[[<<>>,
[<<"10">>,<<"171">>],
[<<"112">>,<<"Gen20267">>],
[<<"52">>,<<"20100812-06:32:30.687">>]]]
4> Pid ! Data.
[[<<>>,
[<<"10">>,<<"171">>],
[<<"112">>,<<"Gen20267">>],
[<<"52">>,<<"20100812-06:32:30.687">>]]]
Got a list [<<>>,
[<<"10">>,<<"171">>],
[<<"112">>,<<"Gen20267">>],
[<<"52">>,<<"20100812-06:32:30.687">>]]
5>
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