How to make Processes Run Parallel in Erlang? - erlang

startTrains() ->
TotalDist = 100,
Trains = [trainA,trainB ],
PID = spawn(fun() ->
train(1,length(Trains)) end),
[ PID ! {self(),TrainData,TotalDist} || TrainData <- Trains],
receive
{_From, Mesg} ->
error_logger:info_msg("~n Mesg ~p ~n",[Mesg])
after 10500 ->
refresh
end.
so, I created Two Processes named trainA, trainB. I want to increment these process by 5 till it gets 100. I made different processes to make each of the train (process) increments its position parallely. But I was surprised to get the output sequentially i.e process trainA ends then process trainB starts. But I want to increment themselves at simultaneously.
I want to run processes like this
trainA 10 trainB 0
trainA 15 trainB 5
....
trainA 100 trainB 100
but I m getting
trainA 0
....
trainA 90
trainA 95
trainA 100
trainA ends
trainB 0
trainB 5
trainB 10
.....
trainB 100
How to make the processes run parallel/simultaneously? Hope you get my Q's. Please help me.

You spawn only one process initialized by function train/2. Your presented code is incomplete so I can only guess but I think your code is wrong because you have only one train process. For inspiration:
-module(trains).
-export([startTrains/0]).
startTrains() ->
TotalDist = 100,
Names = [trainA,trainB ],
Self = self(),
Trains = [spawn_link(fun() ->
train(Name, Self) end) || Name <- Names],
[ Train ! {start, Self, 0, TotalDist} || Train <- Trains],
ok = collectResults(Names).
collectResults([]) -> ok;
collectResults(Trains) ->
receive
{stop, Name, Pos, Length} ->
io:format("~p stops at ~p (~p)~n", [Name, Pos, Length]),
collectResults(Trains -- [Name]);
Msg ->
io:format("Supervisor received unexpected message ~p~n", [Msg]),
collectResults(Trains)
after 10500 -> timeout
end.
train(Name, Sup) ->
receive
{start, Sup, Pos, Length} -> run_train(Name, Sup, Pos, Length);
Msg ->
io:format("~p received unexpected message ~p~n", [Name, Msg]),
train(Name, Sup)
end.
run_train(Name, Sup, Pos, Length)
when Pos < Length ->
receive after 500 ->
NewPos = Pos + 5,
io:format("~p ~p~n", [Name, Pos]),
run_train(Name, Sup, NewPos, Length)
end;
run_train(Name, Sup, Pos, Length) ->
Sup ! {stop, Name, Pos, Length}.
But if I would think it seriously I should look to gen_fsm and OTP principles. But in your current stage keep play with erlang primitives to take better feeling first.

Related

Applying a mutex into an erlang example

I currently have a simple bank account written using erlang, I wish to add a mutex into it so that two deposits cannot be made where the set/get balance can be interupted so that the end value is wrong for example bal A = 10 bal B = 20:
WRONG
get_bal.A 0 → get_bal.B 0 → set_bal.A 10 → set_bal.B 20 == 20
RIGHT
get_bal.A 0 → set_bal.A 10 → get_bal.B 10 → set_bal.B 30 == 30
My code is as follows:
-module(bank).
-export([account/1, start/0, stop/0, deposit/1, get_bal/0, set_bal/1]).
account(Balance) ->
receive
{set, NewBalance} ->
account(NewBalance);
{get, From} ->
From ! {balance, Balance},
account(Balance);
stop -> ok
end.
start() ->
Account_PID = spawn(bank, account, [0]),
register(account_process, Account_PID).
stop() ->
account_process ! stop,
unregister(account_process).
set_bal(B) ->
account_process ! {set, B}.
get_bal() ->
account_process ! {get, self()},
receive
{balance, B} -> B
end.
deposit(Amount) ->
OldBalance = get_bal(),
NewBalance = OldBalance + Amount,
set_bal(NewBalance).
I was wondering if someone could implement the mutex with brief annotations as to explain your thought process. Would be a huge help! Thanks again
The message queue of the account process can provide the effect you seek if you use it correctly. For example, your deposit/1 function has problems because it performs a read-modify-write, where the read and write are two separate actions. Because they're separate, they allow other unrelated actions to sneak in between them and break the math you're performing outside the account.
Why not instead make the account do its own math? After all, the account holds the funds, so it doesn't make sense to do the account calculations outside the account.
account(Balance) ->
receive
{deposit, Amount, From} ->
NewBalance = Balance + Amount,
From ! {deposit, Amount, NewBalance},
account(NewBalance);
{withdraw, Amount, From} when Amount > Balance ->
From ! {error, {insufficient_funds, Amount, Balance}},
account(Balance);
{withdraw, Amount, From} ->
NewBalance = Balance - Amount,
From ! {withdrawal, Amount, NewBalance},
account(NewBalance);
{get, From} ->
From ! {balance, Balance},
account(Balance);
stop -> ok
end.
With this approach, deposit/1 just adds funds atomically and returns the new balance:
deposit(Amount) when Amount > 0 ->
account_process ! {deposit, Amount, self()},
receive
{deposit, Amount, NewBalance} ->
{ok, NewBalance}
end.
Similarly, withdraw/1 just subtracts funds atomically if possible, returning the new balance, or returns an error if an overdraft would occur:
withdraw(Amount) when Amount > 0 ->
account_process ! {withdraw, Amount, self()},
receive
{withdrawal, Amount, NewBalance} ->
{ok, NewBalance};
Error ->
Error
end.
The get_bal/0 function remains the same.
With this approach, all transactions are atomic.

Error handling for stream with Twitter's API. (Blank lines and receive problems)

I'm trying to modify the functionality in my teacher's module for saving tweets from Twitter's Streaming API. The problem is that if I keep the stream open for more than a minute, the API starts sending blank lines to the stream in order to verify its connection.
From what I've understood, the tweets are broken down and then reassembled, but this becomes a problem with the last function in the code below, pop_size.
Pop_size expects the argument to start with a text-representation of a number. So when the blank lines are sent, represented by <<"\r\n">>, the stream crashes with this message:
Error in process <0.118.0> with exit value: {function_clause,
[{twitterminer_source,pop_size,[<<2 bytes>>],[{file,"src/twitterminer_source.erl"}
If I add the line below, does anyone have any suggestions what I should try executing in it?
pop_size(<<"\r\n">>) -> %%Code here!
To clarify: I want the blank line to be disregarded and the loop to continue checking for the next tweets. I'm quite over my head here, but I'll try to answer any follow-up questions as elaborate as I can.
Code: (Three functions)
% Get HTTP chunks and reassemble them into chunks that we get
% as a result of specifying delimited=length.
% https://dev.twitter.com/streaming/overview/processing
split_loop(Sink, Sender, Buffer) ->
case pop_size(Buffer) of
{size, N, Rest} ->
case buffer_pop_n(Rest, N, Sender) of
{pop, Chunk, NewBuf} ->
Sink ! {message, Chunk},
receive next -> ok end,
split_loop(Sink, Sender, NewBuf);
{incomplete, Chunk} -> Sink ! {error, {incomplete, Chunk}};
{terminate, _Chunk} -> Sink ! terminate;
{error, Reason, Chunk} -> Sink ! {error, {Reason, Chunk}}
end;
{more, L} ->
case buffer_pop_n(Buffer, L, Sender) of
{pop, Chunk, NewBuf} ->
split_loop(Sink, Sender, <<Chunk/binary, NewBuf/binary>>);
{incomplete, <<>>} -> Sink ! finished;
{incomplete, Chunk} -> Sink ! {error, {incomplete, Chunk}};
{terminate, _Chunk} -> Sink ! terminate;
{error, Reason, Chunk} -> Sink ! {error, {Reason, Chunk}}
end
end.
% Get a chunk of N bytes from the buffer. If there is not enough data
% in the buffer, get more messages from the pipeline.
buffer_pop_n(B, N, Sender) ->
if
byte_size(B) < N ->
Sender ! next,
receive
{message, Part} ->
Part2 = Part,
buffer_pop_n(<<B/binary, Part2/binary>>, N, Sender);
finished -> {incomplete, B};
terminate -> {terminate, B};
{error, Reason} -> {error, Reason, B}
end;
true -> {pop, binary:part(B, {0, N}), binary:part(B, {N, byte_size(B)-N})}
end.
% We should also support discarding \r\n here
% (see 'blank lines' in https://dev.twitter.com/streaming/overview/messages-types)
pop_size(<<>>) -> {more, 1};
pop_size(<<A,Rest/binary>>) when A >= $0, A =< $9 ->
pop_size((A - $0), 1, Rest);
pop_size(_N, L, <<>>) -> {more, L+1};
pop_size(_N, L, <<"\r">>) -> {more, L+2};
pop_size(N, L, <<A,Rest/binary>>) when A >= $0, A =< $9 ->
pop_size(N * 10 + (A - $0), L+1, Rest);
pop_size(N, _L, <<"\r\n",Rest/binary>>) -> {size, N, Rest}.

Erlang counter expression equivalent to C++, while loop?

Is there an equivalent expression for the increment/decrement operator e.g. counter++?
I also wonder how to properly do this?
-module(whileloop).
-export([call/0, while_loop/2]).
call() ->
while_loop(10,0).
while_loop(Var,Counter) ->
case Var =:= Counter of
false ->
Counter += 1,
whileloop(Var);
end.
edit:
-module(whileloop).
-export([call/0, while_loop/2]).
call() ->
while_loop(10,0).
while_loop(Var, Counter) ->
case Var =:= Counter of
false ->
while_loop(Var,Counter + 1)
end.
The meaning of C += 1 is to modify the value of C. It is a non sense in Erlang since it can only give the following result:
1> C = C+1.
* 1: variable 'C' is unbound
C = 1.
1
3> C = C+1.
** exception error: no match of right hand side value 2
Keep in mind that "A = B" does not mean assigns the value of B to A, but "pattern match" A against B,
if A is unbound then it will bind to A the value of B;
if A =:= B nothing is done, the process continue;
if A =/= B then the process crashes.
So yes, if you want to have a counter, or any information that change, you must use a state variable which is passed as argument of a recursive loop. From this point of view, your last code is correct, but lets follow what happens when you call "call()" in the shell.
first it calls, in the same process - the shell - the function while_loop(10,0).
10 is not equal to 0 so it calls immediately while_loop(10,1).
10 is not equal to 1 so it calls immediately while_loop(10,2).
and so on until it calls while_loop(10,10). Now 10 =:= 10 is true, and this result does not match any clause of the case, so you get an error and the process crash.
As your code does not contain any message receive and simply loop an loop until it crashes, thhe wole process takes only a few micro seconds, so it looks like it fails immediately.
Depending on what you expect, you can imagine several types of counter, here are 2 examples:
-module(counter).
-compile(export_all).
% one counter that help you to count some events
% interface
start_c1(End) when is_integer(End) ->
spawn(?MODULE,counter1,[End]).
start_link_c1(End) when is_integer(End) ->
spawn_link(?MODULE,counter1,[End]).
inc_c1(Pid) when is_pid(Pid) ->
Ref = make_ref(),
Pid ! {inc,self(),Ref},
receive
{Ref,done} -> done;
{Ref,V} -> V
after 1000 ->
{error,no_response}
end.
value_c1(Pid) when is_pid(Pid) ->
Ref = make_ref(),
Pid ! {get_value,self(),Ref},
receive
{Ref,V} -> V
after 1000 ->
{error,no_response}
end.
stop_c1(Pid) when is_pid(Pid) ->
Pid ! stop.
% the counter
counter1(End) -> counter1_loop(End,0).
counter1_loop(End,V) ->
receive
{inc,Pid,Ref} when V =/= done ->
NewV = case V+1 of
End -> done;
Nv -> Nv
end,
Pid ! {Ref,NewV},
counter1_loop(End,NewV);
{inc,Pid,Ref} ->
Pid ! {Ref,done},
counter1_loop(End,done);
{get_value,Pid,Ref} ->
Pid ! {Ref,V},
counter1_loop(End,V);
stop ->
ok
end.
% One kind of timeout that execute something after a while -
% note it exists a similar one in the library
start_after(T,M,F,A) when is_integer(T), is_list(A) ->
Ref = make_ref(),
{Ref,spawn(?MODULE,after_receive,[T,M,F,A,self(),Ref])}.
cancel_after(P) when is_pid(P) ->
P ! cancel.
% the counter
after_receive(T,M,F,A,Pid,Ref) ->
receive
{cancel,Ref} -> Pid ! {after_receive,Ref,cancelled}
after T ->
Pid ! {after_receive,Ref,done},
apply(M,F,A)
end.
and here how to use them:
1> c("../src/counter").
{ok,counter}
2> {Ref,P} = counter:start_after(5000,io,format,["This is the end!" ]).
{#Ref<0.0.0.29>,<0.33.0>}
This is the end!3>
3> {Refa,Pa} = counter:start_after(50000,io,format,["This is the end!" ]).
{#Ref<0.0.0.34>,<0.35.0>}
4> Pa ! {cancel,Refa}.
{cancel,#Ref<0.0.0.34>}
5> flush().
Shell got {after_receive,#Ref<0.0.0.29>,done}
Shell got {after_receive,#Ref<0.0.0.34>,cancelled}
ok
6> P1 = counter:start_c1(5).
<0.52.0>
7> counter:inc_c1(P1).
1
8> counter:inc_c1(P).
{error,no_response}
9> counter:inc_c1(P1).
2
10> counter:inc_c1(P1).
3
11> counter:value_c1(P1).
3
12> counter:inc_c1(P1).
4
13> counter:inc_c1(P1).
done
14> counter:value_c1(P1).
done
15> counter:inc_c1(P1).
done
16> counter:stop_c1(P1).
stop
17> counter:inc_c1(P1).
{error,no_response}
18>
Just recursively call while_loop with the Counter argument incremented by one:
while_loop(Var, Counter + 1)
Your edited version doesn't have a clause when Var =:= Counter and thus crashes. And you'd better use pattern matching in function clauses.
-module(whileloop).
-export([call/0, while_loop/2]).
call() ->
while_loop(10,0).
while_loop(Var, Var) ->
ok;
while_loop(Var, Counter) ->
while_loop(Var, Counter + 1).
And of course you'd need to do something inside the loop. You can use lambdas for that:
-module(whileloop).
-export([call/0, while_loop/3]).
call() ->
while_loop(10, 0, fun(Counter) -> io:format("Counter: ~p~n", [Counter]) end).
while_loop(Var, Var, _) ->
ok;
while_loop(Var, Counter, Fun) ->
Fun(Counter),
while_loop(Var, Counter + 1, Fun).

How can I read the return value of add(N) function in my calc function?

I am new to Erlang, I need to spawn two process running add function, then add the
two numbers.
assigned value of Process one and two is showing the process id, I need catch the value.
How can I read the return value of add(N) function in my calc function?
-module(myerl).
-export([calc/1,add/1]).
add(N) ->
N + 5.
calc(L)
pone = spawn( fun() -> add(A) end),
ptwo = spawn( fun() -> add(B) end),
Result = Pone + Ptwo,
io:format("result ~p~n", [Result]).
You need to use message passing. You must send a message back to the calling process with the result. The spawn function returns a PID (process identifier) to the newly spawned process, not the result of its execution.
This example should do what you're expecting:
calc(A, B) ->
Self = self(), % The spawned funs need a Pid to send to, use a closure
POne = spawn(fun() -> Self ! {self(), add(A)} end),
PTwo = spawn(fun() -> Self ! {self(), add(B)} end),
wait_for_response(POne, PTwo, 0).
wait_for_response(undefined, undefined, Sum) ->
Sum;
wait_for_response(POne, PTwo, Sum) ->
receive
{POne, V} -> wait_for_response(undefined, PTwo, Sum + V);
{PTwo, V} -> wait_for_response(POne, undefined, Sum + V)
end.
#Soup d'Campbells' explanation is good. I instinctively did something slightly different which, in a toy way, anticipates some bad behavior with the child processes. Also, I allow the input to be a list of numbers, not just 2.
-module(myerl).
-export([calc/1, add/1]).
calc(NumList) when is_list(NumList)->
Parent = self(),
_Pids = [spawn(fun()-> Parent ! add(ANum) end) || ANum <- NumList],
collect(length(NumList), 0);
calc(_) ->
{error, badarg}.
collect(0, Sum) ->
Sum;
collect(Cnt, Sum) ->
receive
N when is_number(N) ->
collect(Cnt-1, Sum + N);
_Bad -> % returned something that isnt a number
collect(Cnt-1, Sum)
after 1000 -> % died or is too slow
collect(Cnt-1, Sum)
end.
add(N) ->
N + 5.

How does erlang:now() work?

-module(test_now).
-compile(export_all).
start() ->
{_, A, _} = now(),
loop(0, A).
loop(A) ->
{_, B, _} = now(),
if
B == A + 1 -> loop(0, B);
true -> loop(A)
end.
loop(T, B) ->
{_, C, _} = now(),
if
C == B + 1 -> io:write(T);
true -> loop(T+1, B)
end.
Logically this code should run 1+ second. But the result returns rapidly, far less than one second. And if I invoke test_now:start() in the Eshell frequently (up-arrow, enter,up-arrow, enter...), the results are always 999999ok.
From the documentation (now/0):
It is also guaranteed that subsequent calls to this BIF returns
continuously increasing values. Hence, the return value from now()
can be used to generate unique time-stamps, and if it is called in a
tight loop on a fast machine the time of the node can become skewed.
So you can't use now/0 to check the time like in your example. You can try os:timestamp/0 instead:
start() ->
{_, S, MS} = os:timestamp(),
loop(0, {S, MS}).
loop(T, {S, MS}=Start) ->
{_, S2, MS2} = os:timestamp(),
if
S2 == S + 1 andalso MS2 == MS -> io:format("~p~n", [T]);
true -> loop(T + 1, Start)
end.
Example:
1> timer:tc(test_timestamp, start, []).
13600591
{1000047,ok}
But if you just want to get some notification in one second consider to use erlang:send_after/3 or erlang:start_timer/3:
start() ->
erlang:send_after(1000, self(), timeout),
loop(0).
loop(T) ->
receive
timeout -> io:format("~p~n", [T])
after
0 -> loop(T + 1)
end.
Example:
1> timer:tc(test_timer, start, []).
27433087
{1000520,ok}
It's not enough to check that the seconds component of now/0 has increased if you want to wait for 1 second (i.e. C == B +1 in the if), you also have to take the microseconds component into consideration.
In the extreme case now() = {_, X, 999999}, which means that the seconds component will be X+1 in just 1 microsecond.
I have no idea why you would always get 999999 loops with this solution.

Resources