波斯码BOSSMA Information Technology

Golang在Linux系统中实现微秒级延迟

发布时间:2021年8月25日 / 分类:Go / 1,057 次浏览 / 评论

在程序中延迟或者等待一段时间一般可以使用Sleep函数实现,但是因为操作系统线程调度的消耗,往往只能做到十几或者数十毫秒的精度,很难达到微秒级,Golang的time.Sleep也是如此。

Sleep函数一般都会将当前线程从CPU让出,然后等待操作系统的重新调度,这样可以有效利用CPU资源,但也是Sleep时间精度不高的“罪魁祸首”。因为操作系统线程调度并不是实时的,它会先对线程排队,然后在合适的时机才进行真正的CPU切换,我们可以想象还会有队列优先级以及插队的情况存在。

那么如何才能降低到微秒级呢?本着有现成的就不造轮子的原则,我找遍了各个技术角落也没有找到,当然可能还是有遗漏的地方。不过虽然没有Golang的实现,但是找到了一些C语言版本的延迟函数。参考它们,我实现了Golang的版本,代码如下:

func DelayMicroseconds(us int64) {
	var tv syscall.Timeval
	_ = syscall.Gettimeofday(&tv)

	stratTick := int64(tv.Sec)*int64(1000000) + int64(tv.Usec) + us
	endTick := int64(0)
	for endTick < stratTick {
		_ = syscall.Gettimeofday(&tv)
		endTick = int64(tv.Sec)*int64(1000000) + int64(tv.Usec)
	}
}

你可能会说,这不就是一个死循环吗?!是的,这就是一个死循环,也因此它的名字是Delay,而不是Sleep。

这里边通过系统调用获取了精确到微秒级别的当前时间,然后通过循环不断获取当前时间,与deadline进行比较,在达到或超出deadline时跳出循环,最终实现了指定微秒的时间延迟。

这是目前找到的最好的实现方式了,虽然会导致CPU繁忙,但是也只是在短暂的微秒级别,有时候还是能接受的。

天空飘来五个字,那都不是事,是事也就烦一会,一会就没事。

经过实测这个函数在Linux上可以实现微秒级别的延迟,不过虽然Windows上也有Gettimeofday的系统调用,但是最低只能做到大概500us左右的延迟,通过看源码内部实现机制差别很大。

这段代码用在我编写的一个树莓派硬件驱动库中,如有兴趣欢迎拍砖:https://github.com/bosima/go-pidriver

如果你有更好的方法,欢迎指正。

本博客所有文章如无特别注明均为原创。
复制或转载请以超链接形式注明转自波斯码,原文地址《Golang在Linux系统中实现微秒级延迟

关键字:

建议订阅本站,及时阅读最新文章!
【上一篇】 【下一篇】