perform a function on a fixed time interval

Roberto Ostinelli roberto@REDACTED
Tue Aug 24 12:15:37 CEST 2010


dear list,

i have a loop process which needs to perform a computation every 1000
ms. this process needs also to receive messages from external
processes.

the issue arises from the fact that in every normal erlang loop, the
'after' statement is called only if no messages are receive by the
process for a specific timeout.

this is more or less how i could write a process which executes a
computation every 1000 ms.

the send_loop/2 emulates the external sending of messages, main_loop/1
is the process which must receive external processes messages and
ensure to perform a computation every 1000 ms. you may run the code
from the console with test:start/0.

-----------------------------------

-module(test).
-compile(export_all).

start() ->
	% start main loop
	Pid = spawn(?MODULE, main_loop, [now()]),
	% start sender loop
	send_loop(Pid, 20),
	Pid ! shutdown.

% send 20 messages every 500 ms
send_loop(_Pid, 0) -> ok;
send_loop(Pid, Count) ->
	receive
	after 500 ->
		Pid ! test,
		send_loop(Pid, Count - 1)
	end.

main_loop(LastUpdate) ->
	receive
		shutdown ->
			shutdown;
		test ->
			io:format("received test message~n"),
			Now = now(),
			case timer:now_diff(Now, LastUpdate) / 1000 >= 1000 of
				true ->
					compute(),
					main_loop(Now);
				false ->
					main_loop(LastUpdate)
			end
	after 1000 ->
		compute(),
		main_loop(now())
	end.

compute() ->
	io:format("ping~n").

-----------------------------------

another solution would imply running a timer process which would
signal the main_loop when to perform the computation. you may run the
code from the console with test:start/0.

-----------------------------------

-module(test).
-compile(export_all).

start() ->
	% start main loop
	Pid = spawn(?MODULE, main_loop, []),
	% start sender loop
	send_loop(Pid, 20),
	Pid ! shutdown.

% send 20 messages every 500 ms
send_loop(_Pid, 0) -> ok;
send_loop(Pid, Count) ->
	receive
	after 500 ->
		Pid ! test,
		send_loop(Pid, Count - 1)
	end.

main_loop() ->
	% start timer loop
	TimerPid = spawn(?MODULE, timer, [self()]),
	main_loop(TimerPid).
main_loop(TimerPid) ->
	receive
		shutdown ->
			TimerPid ! shutdown;
		test ->
			io:format("received test message~n"),
			main_loop(TimerPid);
		compute ->
			compute(),
			main_loop(TimerPid)
	end.

% send a ping every 1000 ms to the main_loop
timer(MainPid) ->
	receive
		shutdown ->
			shutdown
	after 1000 ->
		MainPid ! compute,
		timer(MainPid)
	end.
	
compute() ->
	io:format("ping~n").

-----------------------------------

which one would you choose, or is there any other way to perform this better?

thank you,

r.


More information about the erlang-questions mailing list