云服务器价格_云数据库_云主机【优惠】最新活动-搜集站云资讯

大带宽_企业网站分类_12月免费

小七 141 0

在Linux上是时候了

在即将发布的go1.3版本中,一些与计时相关的有趣变化启发我们进一步研究Go程序如何在Linux内核的帮助下保持时间。计时是一个复杂的话题,确定当前时间并不像乍看起来那么简单。在Linux内核上运行已经被用于构建许多重要的系统,比如CloudFlare的RRDNS(我们的DNS服务器)。准确、准确和高效地确定时间是许多此类系统的重要组成部分。要想知道为什么时间是重要的,考虑到人类在说服计算机为他们保留时间方面遇到了一些困难。十年多以前,我们不得不从我们最好的COBOL程序员那里筛选出解决Y2K问题的工具。最近,在处理通过网络时间协议(networktimeprotocol,NTP)传播的闰秒时出现的一个错误也使许多系统离线。正如我们最近几天看到的,NTP对于同步计算机时钟和/或DDoSing它们非常有用。闰秒虫得到了广泛的报道。谷歌已经准备好了,但其他许多热门网站都被关闭了。我们也有2038年的问题值得期待。希望那时仍有一些工程师记得这个32位的东西是怎么回事。出发时间一切都是从作为Go标准库一部分的时间包开始的。time包提供了time、Duration、Ticker、Timer和各种用于操作这些类型的实用程序函数。这个包中最常用的函数可能是时间。现在函数,它将当前时间作为时间结构返回。时间结构有3个字段:类型时间结构{第int64节nsec uintptr公司位置*位置}位置包含时间的时区信息。持续时间用于表示两个时间之间的差异,并配置计时器和计时器。计时器对于实现超时非常有用,通常作为select语句的一部分。Ticker可用于定期唤醒,通常是在for循环中使用select时。Go的时间包在Go标准库的许多其他地方都使用。当处理可能会变慢或完全停止发送数据的套接字连接时,可以使用网络连接接口。我们喜欢在CloudFlare上编写测试,并且有包含某种随机组件的单元测试可以发现有趣的问题。可以使用当前时间在测试中为随机数生成器设定种子,方法是:兰德。新的(兰德新闻源(时间。现在().UnixNano())如果您要为一个安全的应用程序生成随机数,那么您确实希望使用crypto/rand包。有趣的是,即使是加密的初始化/随机读卡器合并当前时间。当前时间还包括使用日志包记录某些内容。一个名为Sourcegraph的非常有用的服务显示了6000多个示例,其中时间。现在被使用。例如,Camlistore代码基调用时间。现在在大约130个不同的地方。与时间。现在既然它无处不在,你有没有想过它是如何工作的?是时候深入研究了。系统调用2012年11月8日,在变更集42c8d3aadc40中,对Go程序在Linux上保持时间的方式进行了最重要的更改。让我们分析一下提交消息和代码,寻找一些线索:运行时:使用vDSO时钟时间。现在& 运行时间.nanotime在Linux/amd64上。除了性能改进,时间。现在()现在在支持的系统上获取真正的纳秒分辨率。为了更好地理解这个提交消息,我们首先需要查看Linux上可用的系统调用,以获得时钟的值。一开始,时间和gettimeofday存在于SVr4,4.3BSD中,在POSIX.1-2001中有描述。time返回自Unix纪元(1970-01-01 00:00:00 UTC)以来的秒数,在C中定义为:时间-时间(时间*时间)32位平台上的时间为4字节,64位平台上的时间为8字节,因此出现了上述Y2038问题。gettimeofday返回自纪元以来的秒数和微秒数,在C中定义为:int gettimeofday(struct timeval*tv,struct timezone*tz)gettimeofday填充结构timeval,该结构具有以下字段:结构时间值{时间\u t tv_秒;/*秒*/suseconds_t tv_usec;/*微秒*/}gettimeofday生成的时间戳的精度只有微秒。POSIX.1-2008将gettimeofday标记为过时,建议改用clock_gettime,它在C中定义为:int clock_gettime(clockid_t clk_id,struct timespec*tp)clock_gettime填充struct timespec,其中包含以下字段:结构时间规范{时间\u t tv_秒;/*秒*/长tv_nsec;/*纳秒*/}时钟可以产生纳秒精度的时间戳。clock ID参数确定要使用的时钟类型。我们感兴趣的是:时钟实时:测量实时性的系统范围的时钟。该时钟受系统时间的不连续跳跃和使用adjtime函数或NTP进行的增量调整的影响。单调时钟:表示从某个未指定的起点开始的单调时间的时钟。该时钟不受系统时间不连续跳变的影响,但受adjtime和NTP的影响。时钟单调性:与时钟单调性相似,但不受adjtime或NTP的调整。时间。现在有了这个背景,我们可以看看时间。现在. (提示:单击godoc中的函数名可以自己查看代码。)这个时间。现在函数是使用now调用的函数实现的,该函数是包时间的内部函数,但实际上是由Go运行时提供的。换句话说,在包时间本身中没有函数的代码。让我们仔细看看386和amd64平台的Linux实现。我们看到这些函数是在汇编程序中实现的,并调用一个函数来检索当前时间。您可能希望看到一个系统调用,即386上的int0x80指令或amd64上的SYSCALL指令,但是Go在Linux上做了一些更有趣的事情。Linux内核提供了虚拟动态链接共享对象(vDSO),作为用户空间应用程序对通常需要对内核进行系统调用的函数进行低开销调用的一种方式。如果您使用glibc语言编写应用程序,那么您可能已经通过vDSO获得了时间。Go不使用glibc,所以它必须在运行时实现这个功能。相关代码在运行时包的vdso_linux_amd64.c中。最后,如果您是那种喜欢盯着操作系统内部的人,这里是vDSO的内核部分。vDSO对时间函数的支持目前仅支持64位,但一个内核补丁正在工作中,可以在32位平台上添加它们。当发生这种情况时,必须更新Go运行时代码才能利用这一点。基准当频繁调用函数来确定时间时,您可能有兴趣知道返回所需的时间。换言之,"现在"到底是怎么回事?为了进行基准测试,您可以直接从Go代码进行这些系统调用。我们为戴夫·切尼(Dave Cheney)出色的autobench项目准备了一个补丁,以便您自己对这些系统调用和其他与时间相关的函数进行基准测试。基准测试还可以帮助我们测量通过vDSO机制调用gettimeofday和clock gettime而不是传统的系统调用路径所节省的时间。我们还将使用autobench来比较同一组时间函数的不同版本Go的性能。下面的所有基准测试数据都是在英特尔酷睿i7-3540M CPU上获得的,它的最高时钟速度为3GHz。CPU频率调整器设置为性能模式,以确保可靠的基准测试结果。我们将使用Go1.2稳定版本作为基线。benchmarkyscalltime和BenchmarkVDSOTime分别测量进行时间系统调用和vDSO调用所需的时间:基准调用时间38.2 ns/op基准值85/3BenchmarkSyscallGettimeofday和BenchmarkVDSOGettimeofday分别测量make调用gettimeofday系统调用和vDSO调用所需的时间:基准测试调用获取每日时间59.3 ns/op基准VdsoGetTimeofDay 23.4 ns/opBenchmarkTimeNow测量调用所需的时间时间。现在,它对clock_gettime(clock_REALTIME)进行底层vDSO调用,并将返回的值转换为时间。时间结构:BenchmarkTimeNow 23.6 ns/操作使用autobench,我们还可以比较不同的Go版本。为了了解我们在过去几年中取得的进展,我们还比较了2012年9月27日发布的Go1.2和Go1.0.3。主要区别在于时间。现在:基准旧ns/op新ns/op增量基准时间现在406 23-94.19%要在go1.0.3中重复这个测试,如果使用的是GCC的最新版本,则需要在变更集419dcca62a3d中进行修复来编译。时钟源判断时间的速度也取决于内核使用的时钟源。要查看可用的时钟源,请运行以下命令:$cat/sys/devices/system/clocksource/clocksource0/available\u时钟源tsc hpet空调泵要查看当前使用的时钟源,请运行以下命令:$cat/sys/devices/system/clocksource/clocksource0/current_时钟源tsc公司时间戳计数器(TSC)是可由RDTSC指令读取的64位寄存器。它的读取速度比高精度事件计时器(HPET)快。ACPI电源管理计时器(APCI PMT)是许多主板上都有的另一个计时器。我们也可以使用上面相同的基准来比较TSC时钟源和HPET时钟源。这样做需要使用clocksource=hpet kernel命令行参数引导Linux。结果如下:基准tsc ns/op hpet ns/op delta基准测试调用日时间59 645+987.69%基准VdsoGetTimeofDay 23 598+2455.56%基准调用时钟获取时间实时58 642+995.56%基准