erlang:now()如何工作?

时间:2012-11-25 07:18:45

标签: 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.

逻辑上,此代码应运行1+秒。但结果迅速恢复,远远不到一秒钟。如果我在Eshell中调用test_now:start() 频繁(向上箭头,输入,向上箭头,请输入...),结果始终为999999ok

2 个答案:

答案 0 :(得分:9)

从文档(now/0):

  

还保证随后对此BIF的调用返回   不断增加价值。因此,从now()返回值   可用于生成唯一的时间戳,如果在a中调用它   在快速机器上紧密循环,节点的时间会变得歪斜。

因此,您无法使用now/0来检查示例中的时间。您可以尝试使用os:timestamp/0

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.

示例:

1> timer:tc(test_timestamp, start, []).
13600591
{1000047,ok}

但如果您只想在一秒钟内收到通知,请考虑使用erlang:send_after/3erlang: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.

示例:

1> timer:tc(test_timer, start, []).
27433087
{1000520,ok}

答案 1 :(得分:1)

如果您想要等待1秒钟(now/0中的C == B +1),检查if的秒组件是否增加是不够的,您还需要微秒组件考虑在内。

在极端情况下now() = {_, X, 999999},这意味着秒组件只需1微秒即可X+1

我不知道为什么你总是会用这个解决方案获得999999循环。