I'm trying to implement a process that I can query/update for some state information (I'm working on an SMS service and want to store some local data based on responses - later I will use a DB but for now I want to use ETS, this is my first Erlang project so I think it's useful to learn). Unfortunately it seems like my inserts are not coming through and I don't understand why. This is the module:
-module(st).
-compile(export_all).
maintain_state() ->
Tab = ets:new(state, [set]),
receive
{Pid, lookup, Key} ->
Pid ! ets:lookup(Tab, Key),
maintain_state();
{Pid, update, Key, Handler} ->
NewState = Handler(ets:lookup(Tab, Key)),
Status = ets:insert(Tab, NewState),
Pid ! {Status, NewState},
maintain_state();
{Pid, statelist} ->
Pid ! ets:tab2list(Tab),
maintain_state();
kill ->
void
end,
ets:delete(Tab).
start_state_maintainer() ->
Pid = spawn(st, maintain_state, []),
register(state, Pid).
update_state(StateHandler) ->
state ! {self(), update, testing, StateHandler},
receive
After ->
After
after 1000 ->
throw("Timeout in update_state")
end.
lookup_state() ->
state ! {self(), lookup, testing},
receive
Value ->
Value
after 1000 ->
throw("Timeout in lookup_state")
end.
all_state() ->
state ! {self(), statelist},
receive
Value ->
Value
after 1000 ->
throw("Timeout in all_state")
end.
Which I then load in an erl session:
> c(st).
> st:start_state_maintainer().
> st:lookup_state().
[]
> st:update_state(fun (St) -> {testing, myval} end).
{true, {testing, myval}}
> st:all_state().
[]
Since update_state shows true I figured the insert was successful, but nothing seems to be stored in the table. What am I doing wrong?
PS: if this whole approach is flawed or you have other remarks about my code I would appreciate those as well.
Ok. Let's run your code again.
1> c(st). % compile your code
{ok,st}
% Before doing anything. let's get count of all ETS tables using ets:all/0
2> length(ets:all()).
16 % So the Erlang VM has 16 tables after starting it
3> st:start_state_maintainer().
true
% Let's check count of tables again:
4> length(ets:all()).
17 % Your process has created its own table
5> st:lookup_state().
[]
% Check count of tables again
6> length(ets:all()).
18 % Why????
7> st:update_state(fun (St) -> {testing, myval} end).
{true,{testing,myval}}
8> length(ets:all()).
19
9> st:all_state().
[]
10> length(ets:all()).
20
So in line 5 in function maintain_state/0 you are creating an ETS table and in lines 9, 14 and 17 you are calling this function again ! So after receiving each message (except void) you are creating new ETS table!
Let's see those tables:
11> P = whereis(state). % Get process id of 'state' and assign it to P
<0.66.0>
12> Foreach =
fun(Tab) ->
case ets:info(Tab, owner) of
P -> % If owner of table is state's pid
io:format("Table ~p with data ~p~n"
,[Tab, ets:tab2list(Tab)]);
_ ->
ok
end
end.
#Fun<erl_eval.6.118419387>
13> lists:foreach(Foreach, ets:all()).
Table 28691 with data []
Table 24594 with data []
Table 20497 with data [{testing,myval}]
Table 16400 with data []
ok
And after killing your process, We should have 16 tables again:
14> exit(P, kill).
true
15> length(ets:all()).
16
You have two choises. You can use named tables like this:
maintain_state() ->
% With 'named_table' option, we can use the name of table in code:
Tab = ets:new(state, [set, named_table]),
maintain_state2().
maintain_state2() ->
receive
{Pid, lookup, Key} ->
Pid ! ets:lookup(state, Key), % I used name of table
maintain_state2();
...
Or use table as argument of maintain_state2:
maintain_state() ->
Tab = ets:new(state, [set]),
maintain_state2(Tab).
maintain_state2(Tab) ->
receive
{Pid, lookup, Key} ->
Pid ! ets:lookup(Tab, Key),
maintain_state2(Tab);
...
I changed the code to one of above examples and here is the result:
1> st:start_state_maintainer().
true
2> st:lookup_state().
[]
3> st:update_state(fun (St) -> {testing, myval} end).
{true,{testing,myval}}
4> st:all_state().
[{testing,myval}]
5> length(ets:all()).
17
After playing with Erlang's message passing and understanding its functionality and its concepts, I really suggest you to learn OTP design principles and OTP behaviors like gen_server and use them instead of writing your own receive ... and Pid ! ... statements.
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 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.
I'm applying the following command to two erlang prompts, they all generate the same sequence of random number, so does it mean it is pseudo random in Erlang language? I'm curious about the rationale, since in Java, the sequence will not be the same even if I provide it with the same seed for two times. Many thanks!
random:seed(6, 6, 6).
random:uniform(100).
random:uniform(100).
...
the generated sequence: 12, 27, 79, 58, 90, 25, ...
What you're describing is generally how traditional pseudorandom number generators (PRNGs) have always worked, including Erlang's random module, which I think implements Wichman-Hill, but today's PRNGs are necessarily more sophisticated. In Erlang 18 you'll find a new rand module that does not suffer the problem you're describing.
As you can see from the shell session copied below, you can just call the rand:uniform/0,1 functions from different processes without seeding, and the initial numbers in the various processes will be different:
1> rand:uniform().
0.10584199892675317
2> Self = self().
<0.1573.0>
3> f(R), spawn(fun() -> Self ! rand:uniform() end), receive R -> R end.
0.9124422823012622
4> f(R), spawn(fun() -> Self ! rand:uniform() end), receive R -> R end.
0.9476479571869831
5> f(R), spawn(fun() -> Self ! rand:uniform() end), receive R -> R end.
0.037189460750910064
6> f(R), spawn(fun() -> Self ! rand:uniform() end), receive R -> R end.
0.17698653918897836
The first call runs directly in the shell process. We then get the shell's pid, store it into Self, and spawn four processes in succession that each send the results of rand:uniform/0 back to the shell, which receives it into R. As you can see, the four spawned processes each return different values, all of which differ from the value the shell got when it first ran rand:uniform/0.
If you want a number in a range other than 0-1, pass an integer N to rand:uniform/1 and you'll get a value V in the range 1 <= V <= N:
7> f(R), spawn(fun() -> Self ! rand:uniform(1234567) end), receive R -> R end.
510226
8> f(R), spawn(fun() -> Self ! rand:uniform(1234567) end), receive R -> R end.
562646
9> f(R), spawn(fun() -> Self ! rand:uniform(1234567) end), receive R -> R end.
250637
10> f(R), spawn(fun() -> Self ! rand:uniform(1234567) end), receive R -> R end.
820871
11> f(R), spawn(fun() -> Self ! rand:uniform(1234567) end), receive R -> R end.
121252
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
I've been making a chat application in Erlang for a school project, but I've run into an issue. I'm trying to make my program concurrent and in order to do so I start a new thread for each message a channel is sending. I do this using lists:foreach, but I want to make sure that I don't message the person who typed in the channel.
request(State, {message, {UserID,UserPID}, Token}) ->
case catch lists:member({UserID,UserPID}, State#channel.users) of
false ->
{{error, user_not_joined}, State};
true ->
spawn( fun() ->
ListOfUsers = State#channel.users,
UserPIDs = lists:map(fun ({_, V}) -> V end, ListOfUsers),
%spawn( fun() ->end)
lists:foreach(
fun(UserPID) -> ok end,
fun(PID) ->
spawn( fun() -> genserver:request(PID, {message_from_server, State#channel.name, UserID, Token}) end)
end, UserPIDs) end),
{ok, State}
end;
What I pretty much want to do is to match with the UserPID inside the foreach. As of now I only get warnings:
channel.erl:39: Warning: variable 'UserPID' is unused
channel.erl:39: Warning: variable 'UserPID' shadowed in 'fun'
Line 3 is fun(UserPID) -> ok end,
Cheers
The answer by legoscia is fine, but I'd add that often list comprehension is simpler to use and simpler to read than lists:foreach. Note that list comprehension is able to ignore values based on clauses. Consider the following example:
-module(filter).
-export([do/0]).
do() ->
Values = lists:seq(1,10),
IgnoreThisValue = 5,
%% print all values unequal to IgnoreThisValue
[io:format("Value: ~b~n", [Value]) ||
Value <- Values, Value =/= IgnoreThisValue],
ok.
Run it in the shell:
1> make:all([load]).
Recompile: filter
up_to_date
2> filter:do().
Value: 1
Value: 2
Value: 3
Value: 4
Value: 6
Value: 7
Value: 8
Value: 9
Value: 10
A side note on your code: Why do you spawn a thread per process? I assume that you are using the behaviour gen_server (correct me if I am wrong). If so, you should consider using the cast function to simply send a message. As you do not check the result of genserver:request/2, this might be a viable option which saves you a lot of processes.
Since the function argument shadows the existing variable, you need to use a guard for that:
fun(PID) when PID =:= UserPID -> ok end