Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does erlang:now() work?

Tags:

erlang

eshell

-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.

like image 539
wizawu Avatar asked Feb 21 '26 02:02

wizawu


1 Answers

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}
like image 58
hdima Avatar answered Feb 23 '26 02:02

hdima



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!