【问题标题】:Make python script exit after x seconds of inactivity在 x 秒不活动后退出 python 脚本
【发布时间】:2015-06-26 23:05:23
【问题描述】:

我有一个用于我的树莓派的脚本,它不断地读取数据并将数据保存到一个文件中。但是我知道这很危险,因为如果在保存数据时拔掉电源,SD 卡确实存在损坏的风险。

如果计算机在一段时间内处于非活动状态,我是否可以让脚本自行终止?

对不起,如果这个问题含糊不清,但我什至不知道从哪里开始,所以我无法显示我尝试过的任何代码。

【问题讨论】:

  • 您如何检查活动
  • 我还不确定 100%,这显然是个问题。但是现在,我想如果没有来自键盘的输入,我希望它停止,所以我有一个工作示例
  • 你认为什么是不活跃的?
  • @PadraicCunningham 假设现在两分钟没有键盘输入
  • @PaulyD 我猜你的意思不是键盘输入到你的脚本,而是键盘输入一般?如果是这样,您的脚本无法单独执行此操作,因为键盘输入永远不会到达它。

标签: python timer raspberry-pi exit


【解决方案1】:

这是一个幼稚的看门狗实现:

import os
import signal
import threading



class Watchdog():
    def __init__(self, timeout=10):
        self.timeout = timeout
        self._t = None

    def do_expire(self):
        os.kill(os.getpid(),signal.SIGKILL)

    def _expire(self):
        print("\nWatchdog expire")
        self.do_expire()

    def start(self):
        if self._t is None:
            self._t = threading.Timer(self.timeout, self._expire)
            self._t.start()

    def stop(self):
        if self._t is not None:
            self._t.cancel()
            self._t = None

    def refresh(self):
        if self._t is not None:
             self.stop()
             self.start()

wd = Watchdog() 构建它,每次你得到一些可以满足你工作需求的东西时,就打电话给wd.refresh()。如果您在超时结束前不调用刷新,它将调用os.kill(os.getpid(),signal.SIGKILL)

您不能只使用sys.exit(),因为它只会引发SystemExit 异常:使用kill 可以随心所欲。

现在您可以使用一些东西来轮询系统并使用答案来刷新或不刷新看门狗。比如xprintidle告诉你X空闲时间,但都取决于你需要监控什么。

使用示例

timeout=10
wd = Watchdog(timeout)
wd.start()
while True:
    a=str(raw_input('Tell me something or I will die in {} seconds: '.format(timeout)))
    wd.refresh()
    print("You wrote '{}'... you win an other cycle".format(a[:-1))

【讨论】:

  • 问题的难点在于如何检测“系统活动”并重置计时器。
  • @abarnert 也许你是对的,但 OP 并不清楚这一点......无论如何,这个答案至少可以涵盖标题:)
  • @abarnert 只是为了理解:问题中更难的部分是什么?输入 google linux detect system inactivity 或猜测 OP 想要什么? :)
  • 嗯,是的,读心术通常是 SO 上许多问题中最难的部分。 :) 但是,如果您阅读了有关该问题的 cmets,则此 OP 确实回答了一些后续问题。显然,如果他将实际问题编辑到问题中会更好(或者如果他一开始就是这样写的),但我认为你不需要再去猜测了。
  • @Micheled'Amico 感谢您输入此内容,但它对我不起作用 :( 该脚本只是要求输入,不做任何其他事情,它不会关闭它,我不知道如何让它这样做
【解决方案2】:

xprintidle 实用程序,可以轻松完成任务:

#!/usr/bin/env python
# encoding: utf-8

import subprocess as sp
import threading
import time
import sys

def quit_on_idle(threshold=2000):
    import thread
    # note that sys.stdout.write and .flush should rather be used
    # instead of print
    while True:
        try:
            idle = float(sp.check_output('xprintidle').strip())
            if idle > threshold:
                print 'Inactive for {} seconds'.format(idle / 1000)
                break
        except (ValueError, sp.CalledProcessError) as err:
            print 'An error occured'
            # add your error handling here
        time.sleep(0.2)
    thread.interrupt_main()

try:
    threading.Thread(target=quit_on_idle).start()
    print 'Watchdog has been started in a separate thread'
    time.sleep(1)
    print 'one second passed'
    time.sleep(3)
    print 'This may not run at all, if you left computer idle'
except KeyboardInterrupt:
    print 'Bye'

【讨论】:

  • 感谢您的帮助,但是当我尝试在我的 pi 上运行它时,我得到了这些错误: Traceback(最近一次调用最后一次):文件“timer.py”,第 12 行,在 空闲= float(sp.check_output('xprintidle').strip()) 文件“/usr/lib/python2.7/subprocess.py”,第 537 行,在 check_output 过程中 = Popen(stdout=PIPE, *popenargs, ** kwargs)文件“/usr/lib/python2.7/subprocess.py”,第 679 行,在 init 中 errread, errwrite)文件“/usr/lib/python2.7/subprocess.py”,第 1259 行,在 _execute_child raise child_exception OSError: [Errno 2] No such file or directory
  • 你需要先安装xprintidle,它是一个用C写的二进制文件;见packages.debian.org/sid/xprintidle
  • 好的,非常感谢!现在可以了,伯特你知道有没有办法让这个计时器独立于程序的其余部分?
  • 将其放入函数中并在单独的线程中运行,请参阅更新版本。有关更多详细信息,请阅读有关 threading 模块的文档。
【解决方案3】:

我为 python 包装了 xprintidle,我很想看看它是否能满足你的要求!

https://pypi.python.org/pypi/xprintidle

安装:

pip install xprintidle

使用方法:

import xprintidle
print xprintidle.idle_time()

让我知道你的进展:)

【讨论】:

    【解决方案4】:

    您可以调用 libXss.XScreenSaverQueryInfo() 函数来获取空闲时间,就像 X 中的屏幕保护程序一样。纯 Python pxss.py 显示了它是如何完成的。下载它并将其与您的代码放在一起:

    #!/usr/bin/env python
    from __future__ import division
    import os
    import signal
    import time
    
    # $ wget https://raw.githubusercontent.com/mariano/snakefire/9437e59ffe9deff83676c5101a0dbf694ad3344b/snakefire/pxss.py
    import pxss
    
    def watchdog(timeout, idle_callback):
        """Call *idle_callback* after *timeout* seconds of inactivity."""
        tracker = pxss.IdleTracker(idle_threshold=timeout*1000)
        while True:
            state_change, wait_time, _ = tracker.check_idle()
            if state_change == "idle":
                idle_callback()
            time.sleep(wait_time / 1000)
    
    def die():
        """thread.interrupt_main() analog."""
        os.kill(os.getpid(), signal.SIGINT)
    

    例子:

    import sys
    import threading
    from itertools import cycle
    
    # exit after 10 seconds of inactivity
    t = threading.Thread(target=watchdog, args=[10, die])
    t.daemon = True
    t.start()
    
    # do whatever you like here that can be interrupted by Ctrl+C
    try:
        for c in cycle('/|\-'):
            sys.stderr.write('\b' + c)
            sys.stderr.flush()
            time.sleep(.2)
    except KeyboardInterrupt:
        print('bye')
    

    【讨论】:

      猜你喜欢
      • 2019-12-25
      • 1970-01-01
      • 2020-02-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-07-30
      相关资源
      最近更新 更多