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+2番目に実行されるはずです。しかし、結果は1秒よりはるかに短い時間で返されます。test_now:start()また、Eshellを頻繁に呼び出すと(上矢印、Enter、上矢印、Enter ...)、結果は常に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}

ただし、1秒以内に通知を受け取りたい場合は、erlang:send_after / 3または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.

例:

1> timer:tc(test_timer, start, []).
27433087
{1000520,ok}
于 2012-11-25T11:35:16.043 に答える
1

now/01 秒 (つまりC == B +1で) 待機する場合、 の秒コンポーネントが増加したことを確認するだけでは十分ではありませんif。マイクロ秒コンポーネントも考慮する必要があります。

極端な場合now() = {_, X, 999999}は、秒のコンポーネントがX+1わずか 1 マイクロ秒になることを意味します。

このソリューションで常に 999999 ループが発生する理由がわかりません。

于 2012-11-25T10:37:42.627 に答える