检测系统在循环中挂起

Posted

技术标签:

【中文标题】检测系统在循环中挂起【英文标题】:Detecting system suspend in a loop 【发布时间】:2018-06-10 16:07:04 【问题描述】:

我正在尝试使用以下算法检测系统挂起:

while True:
    lastchecked = now()
    if now() - lastchecked > 1s: print "suspend detected!"

但是我遇到了一个问题:如果挂起发生在第 2 行和第 3 行之间,那么循环会捕获它。但是如果挂起发生在第一行和第二行之间,那么算法就会失败。

这种情况有什么常用的方法吗?最好是独立于操作系统的,我不想挂钩操作系统事件等。

【问题讨论】:

看起来像XY problem。请添加您想要达到的目标的详细信息 - 一定有比投票更好的方法。 在绝大多数情况下,您不需要检查系统是否挂起——一个设计良好的算法会简单地从它停止的地方继续。这就是系统挂起的全部目的。 我的程序是一种系统监视器类型的应用程序——它需要知道系统是否进入休眠状态以及休眠了多长时间。 【参考方案1】:

首先,polling is inferiour to notifications 因为它浪费了系统资源,而这些资源本来可以花在有用的工作上(你当前的循环也是busy loop)。当然,电源管理事件系统是特定于操作系统的(请参阅Power Management Notifications in Linux 和 how to hook to events / messages in windows using python),但如果您正在编写系统监视器应用程序,无论如何您都无法隐藏操作系统差异。


现在,这里的关键是在内存中总是有两个时间戳并覆盖旧的:

T1
  \
   T2
   <- compare
  / 
T3
 <- compare
  \
   T4
   etc
  /

然后,无论何时发生挂起,下一个时间戳都会设置得比它应该设置的晚,并且比较会看到差异。

这样,您甚至不需要每秒钟左右轮询一次!您的轮询间隔只需与您想要检测的最短暂停时间一样短。例如。如果您想检测至少 30 秒的暂停时间,您只需每 30 秒轮询一次:如果系统睡眠时间更长,则可以保证“错过一个节拍”。

i=0
poll_period=30
t=[time.time()]*2
while True:
    # actually, poll period will be slightly longer due to code overhead:
    # https://***.com/questions/26774186/looping-at-a-constant-rate-with-high-precision-for-signal-sampling
    # but that doesn't make a difference in this case
    time.sleep(poll_period)
    t[i]=time.time()
    if t[i] - t[(i+1)%2] > poll_period + 2: print "suspend detected"
    i = (i+1)%2

请注意you will get false positives if your process gets preempted by others。这也是为什么使用系统通知是一种非常优越的方式的另一个原因。

【讨论】:

如果我想在循环中加入更多的函数调用,放在哪里重要吗? @user2108462 不是真的,但如果它们都在time.sleep() 的同一侧,那可能会更容易——那么您将确定哪个代码的开销是哪个测量间隔的一部分。 【参考方案2】:

我认为这个算法有效:

last1 = now()
last2 = now()
while True:
    last1 = now()
    if now() - last1 > 1s or now() - last2 > 1s: print "suspend detected!"
    last2 = now()
    if now() - last1 > 1s or now() - last2 > 1s: print "suspend detected!"

这将在 while 循环中的任何行之后立即检测到暂停:

第一行之后的挂起将被第二行检测到(因为 last1 将是旧的)。 第 4 行将检测到第二行之后的挂起(因为 last1 将是旧的)。 第 3 行之后的挂起将被第 4 行检测到(因为 last1 和 last2 都将是旧的)。 第 4 行之后的挂起将被第 2 行检测到(因为 last2 将是旧的)。

我相信这是检测系统挂起所需的最少代码量。如果我错了,请纠正我。

【讨论】:

仍然是一个繁忙的循环

以上是关于检测系统在循环中挂起的主要内容,如果未能解决你的问题,请参考以下文章

限制导航以防止浏览器在 React App 中挂起

UIViewController 在 Xcode 7 中挂起

Ktor HttpClient 在 runBlocking 中挂起

VisualVM 校准步骤在 Windows 10 中挂起

Julia 在 HTTP WebSocket 块中挂起异常

rails控制台在生产环境中挂起