gpt4 book ai didi

python - 我们如何在 Linux 中使用 sleep() 来保持合理的 CPU 使用率,同时仍然具有良好的计时精度?

转载 作者:可可西里 更新时间:2023-11-01 11:52:27 46 4
gpt4 key购买 nike

问题

我正在尝试测试一个使用 UDP 数据包以预定速率进行通信的系统。我希望能够使用具有设定数据包速率的 Python 测试工具来测试该系统。采样率可能是 20 个数据包/秒或 4500 个数据包/秒等。

在一些简单的测试中,我确定我的 Windows 机器每秒可以通过本地主机传递超过 150,000 个 UDP 数据包,因此我可以将其视为实验的上限。

让我们从这个 shell 结构开始创建一个速率限制器。此代码的灵感主要来自 this thread 中的代码.

方法一

import time, timeit

class RateLimiter:

def __init__(self, rate_limit):
self.min_interval = 1.0 / float(rate_limit)
self.last_time_called = None

def execute(self, func, *args, **kwargs):
if self.last_time_called is not None:
# Sleep until we should wake up
while True:
now = timeit.default_timer()
elapsed = now - self.last_time_called
left_to_wait = self.min_interval - elapsed

if left_to_wait <= 0:
break

time.sleep(left_to_wait)

self.last_time_called = timeit.default_timer()
return func(*args, **kwargs)

您可以像这样使用这个辅助类:

self._limiter = RateLimiter(4500)   # 4500 executions/sec

while True:
self._limiter.execute(do_stuff, param1, param2)

timeit.default_timer() 的调用是 Python 中的一个快捷方式,可为您的平台提供最高精度的计时器,在 Windows 和 Linux 上的精度约为 1e-6 秒,这我们需要。

方法 1 的性能

在这种方法中,sleep() 可以在不消耗 CPU 周期的情况下为您争取时间,但它会损害延迟的准确性。 This comment显示 Windows 和 Linux 之间关于 sleep() 小于 10ms 的差异。总结该评论,Windows 的 sleep() 仅适用于 1ms 或更多的值(任何小于都被视为零)但通常 sleep 时间少于请求的 sleep 时间时间,而在 Linux 中 sleep() 更精确,但通常 sleep 时间比请求的时间略更多

上面的代码在我的 Windows 机器上是准确的,但对于更快的速度来说效率低下。当我在测试中请求 4500 个数据包/秒的速率时,我得到的中值为 4466 个数据包/秒(0.75% 误差)。 但是,对于高于 1000Hz 的速率,对 sleep() 的调用需要零时间,因此 RateLimiter 会消耗 CPU 周期,直到超过等待时间。不幸的是,我们别无选择,因为我们不能在 Windows 中使用小于 1 毫秒的非零 sleep 时间。

在 Linux 中,对 sleep() 的调用花费的时间比请求的时间长,产生的中值为每秒 3470 个数据包(22.8% 的错误)。虽然 Linux 中的 sleep() 花费的时间比预期的要长,但请求更高的频率(如 6000Hz)会产生高于 4500 的真实频率,因此我们知道它能够达到目标频率。问题出在我们的 sleep() 值中,必须将其更正为低于我们预期的值。我使用以下(错误的)方法执行了另一个测试。

方法二

在这种方法中,我们从不 sleep 。我们消耗 CPU 周期直到时间过去,这导致 Python 100% 使用它运行的核心:

def execute(self, func, *args, **kwargs):
if self.last_time_called is not None:
# Sleep until we should wake up
while True:
now = timeit.default_timer()
elapsed = now - self.last_time_called
left_to_wait = self.min_interval - elapsed

if left_to_wait <= 0:
break

# (sleep removed from here)

self.last_time_called = timeit.default_timer()
return func(*args, **kwargs)

方法 2 的性能

在 Linux 中,这会产生 4488 个数据包/秒的中位数速率(0.26% 错误),这与 Windows 相当,但同样占用 CPU,因此效率非常低。

问题

这就是我的意思。 我们如何在 Linux 中使用 sleep() 来保持合理的 CPU 使用率,同时仍具有良好的计时精度?

我认为这必须涉及某种监控和补偿流程,但我不太确定如何着手实现这样的事情。是否有解决此类纠错问题的标准方法?

最佳答案

保证这一点的唯一方法是使用实​​时操作系统调度。否则,您将受到调度程序的摆布,并可能随时被抢占(例如,如果有一些高优先级/低 nice 进程正在占用您的 CPU 周期)。事实上,sleep() 只是一种请求抢占特定持续时间的便捷方式。您总是有可能睡得比您要求的时间长得多。这就是 Windows 甚至不尝试休眠 <1ms 的原因;一旦考虑到调度程序的不确定性,它就无法达到那种精度。开箱即用,Linux 也不是,但它可以配置(通过 sched_setscheduler(2) )是实时的,所以如果你问它会尝试。

关于python - 我们如何在 Linux 中使用 sleep() 来保持合理的 CPU 使用率,同时仍然具有良好的计时精度?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27113720/

46 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com