2
-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+第二个运行。但结果返回很快,远不到一秒。如果我经常test_now:start()在 Eshell 中调用(向上箭头、回车、向上箭头、回车...),结果总是.999999ok

4

2 回答 2

9

从文档(now/0):

还可以保证对该 BIF 的后续调用返回不断增加的值。因此,now() 的返回值可用于生成唯一的时间戳,如果在快速机器上的紧密循环中调用它,则节点的时间可能会出现偏差。

所以你不能使用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}
于 2012-11-25T11:35:16.043 回答
1

如果now/0要等待 1 秒(即C == B +1if

在极端情况下now() = {_, X, 999999},这意味着秒组件将X+1在 1 微秒内。

我不知道为什么使用此解决方案您总是会得到 999999 个循环。

于 2012-11-25T10:37:42.627 回答