erlang 时间函数

https://blog.csdn.net/mycwq/article/details/45346411

很多人会注意到这个问题,erlang提供了2个时间函数,erlang:now() 和 os:timestamp()。用法一样,都是返回当前的时间。具体时间是从1970年1月1日零时算起,到现在经过的时间,结果为{MegaSecs, Secs, MicroSecs}。

这两个函数有什么区别?

os:timestamp() 获取到的时间为操作系统的时间,不做任何修正;而erlang:now(),每次获取都会确保生成了唯一的时间,就是说,erlang:now()在实现上对时间做了一个校正,每次都生成一个单调向前的唯一值。

erlang:now()的特点:
Monotonicerlang:now() never jumps backwards - it always moves forwardInterval correctThe interval between two erlang:now() calls is expected to correspond to the correct time in real life (as defined by an atomic clock, or better)Absolute correctnessThe erlang:now/0 value should be possible to convert to an absolute and correct date-time, corresponding to the real world date and time (the wall clock)System correspondenceThe erlang:now/0 value converted to a date-time is expected to correspond to times given by other programs on the system (or by functions like os:timestamp/0)UniqueNo two calls to erlang:now on one Erlang node should return the same value

主要是这3个特点:
特点
说明
单调向前
erlang:now() 获取的时间是单调向前,就算系统时间倒退了,也不会影响这个函数的使用。(时间依旧是向前的,较之前几乎没有偏差)
唯一性
erlang:now() 获取的值都是唯一的,不会重复出现2个相同的值。
间隔修正
两次 erlang:now() 调用的间隔都可以被利用来修正erlang时间。
到这里,可以看出 erlang 内部实现了一套时间校正的机制,当系统时间出错的时候,就会做修正。(关于这块内容,可以看Erlang相关文档 time correction)

erlang 时间校正
时间校正的作用:
在开始这段内容前,讲讲时间校正的作用
1. 时间单调向前:
  举个例子,说明时间倒退问题:
  比如,游戏中会统计今天和昨天杀怪的总数量,跨零点时要把今天杀怪字段的数量写到昨天的字段,然后将今天的置0。跨零点后,如果时间倒退了几秒钟,然后就会重复跨零点。那么,今天的数量会覆盖昨天的数量,导致昨天的数量被清零。

2. 时间平稳:
  同样举个例子,说明时间不平稳问题:
  比如,erlang开发中,经常都会出现一个进程call另一个进程的场景,一般是5秒超时,假如时间突然加快了5秒,就相当于没有等待操作完成,就直接超时了。当然这是很不合理的

erlang时间校正的特点:
MonotonicThe clock should not move backwardsIntervals should be near the truthWe want the actual time (as measured by an atomic clock or an astronomer) that passes between two time stamps, T1 and T2, to be as near to T2 - T1 as possible.Tight coupling to the wall clockWe want a timer that is to be fired when the wall clock reaches a time in the future, to fire as near to that point in time as possible

假如操作系统时间出现了改变,erlang不会立刻改变内部时间为系统时间,而是将时间轻微加快或减慢,最终和系统时间保持一致。就算系统时间突然倒退到以前的某个时间,但时间总是向前这点是不会改变的,所以,erlang只是预期在将来某个时间和系统时间达成一致,而不会倒退时间。

erlang是怎么校正时间的?
erlang内部时间会和系统挂钟时间保持同步,当系统挂钟时间突然改变时,erlang会比较两个时间的差异,让内部的时间的同步值轻微变大或变小,幅度最大是1%,就是说,VM经历 1s 实际上可能就是 0.99s 或者1.01s。当系统时间改变了1分钟,erlang会花100分钟来慢慢校正,并最终和系统时间保持同步。

哪些函数受到时间校正影响?
erlang:now/0The infamous erlang:now/0 function uses time correction so that differences between two "now-timestamps" will correspond to other timeouts in the system. erlang:now/0 also holds other properties, discussed later.receive ... afterTimeouts on receive uses time correction to determine a stable timeout interval.The timer moduleAs the timer module uses other built in functions which deliver corrected time, the timer module itself works with corrected time.erlang:start_timer/3 and erlang:send_after/3The timer BIF's work with corrected time, so that they will not fire prematurely or too late due to changes in the wall clock time.
不只是 erlang:now() ,以上几个功能都有赖于时间校正的实现。比如 erlang:send_after/3 , 就算系统时间改变了,这个函数发出的消息也会按预定时间期限送达。

结束语
最后,说下时间校正的副作用。
erlang实现时间校正有计算开销的,而且这个内部校正值是全局变量,不只是所有erlang进程,还是VM所有调度线程都会读写这个时间,所以就要有锁来保证数据安全。为此,erlang内部设定好了 erlang:now/0 调用频率不会超过1微妙1次。
当然,如果获取时间只是用于测试目的,或者打印错误日志时间,完全可以用 os:timestamp/0 来代替。对于一些有大规模进程的项目,还可以设立一些时间管理进程,用于同步时间,而每个进程只要读取自己的进程字典就好。

如果不想使用,还可以禁用这个功能。
Time correction is enabled or disabled by passing the +c [true|false] command line argument to erl.

--------------------- 
作者:没有开花的树 
来源:CSDN 
原文:https://blog.csdn.net/mycwq/article/details/45346411 
版权声明:本文为博主原创文章,转载请附上博文链接!

你可能感兴趣的:(erlang)