繁体   English   中英

线程被阻止调用阻止-如何在阻止调用上超时?

[英]A thread is blocked by a blocking call - how do I make a timeout on the blocking call?

我有一个运行外部程序并启动超时线程的python程序。 超时线程应倒计时10分钟,并且如果操作外部程序的脚本在该时间内未完成,则应终止该外部程序。

乍一看,我的线程似乎运行良好,我的主脚本和线程同时运行,没有任何问题。 但是,如果外部程序中出现一个弹出窗口,它将停止我的脚本,以至于倒数线程也停止计数,因此完全无法正常工作。

我认为问题是该脚本在外部程序的API中调用了阻止功能 ,该功能被弹出窗口阻止。 我知道为什么它阻止了我的主程序,但不明白为什么它阻止了我的倒数线程。 因此,一种可能的解决方案可能是为倒计时运行一个单独的脚本,但是我想保持其尽可能干净,为此启动脚本似乎很麻烦。

我到处都在寻找线索,但没有找到太多。 这里有一个对gevent库的引用: Python中的background函数 ,但这似乎是一项基本任务,我不想为此添加外部库。

我还发现它采用的是Windows多媒体计时器的解决方案在这里 ,但我从来没有与这个工作前,恐怕代码将不会与这种灵活。 脚本仅适用于Windows,但它应能在XP及更高版本的所有Windows上使用。

对于Unix,我找到了signal.alarm,它似乎完全符合我的要求,但不适用于Windows。 还有其他选择吗?

关于如何以最简化的方式进行操作的任何想法?

这是我正在创建的简化线程(在IDLE中运行以重现该问题):

import threading
import time

class timeToKill():
    def __init__(self, minutesBeforeTimeout):
        self.stop = threading.Event()
        self.countdownFrom = minutesBeforeTimeout * 60

    def startCountdown(self):
        self.countdownThread= threading.Thread(target=self.countdown, args=(self.countdownFrom,))
        self.countdownThread.start()

    def stopCountdown(self):
        self.stop.set()
        self.countdownThread.join()

    def countdown(self,seconds):
        for second in range(seconds):
            if(self.stop.is_set()):
                break
            else:
                print (second)
                time.sleep(1)

timeout = timeToKill(1)
timeout.startCountdown()
raw_input("Blocking call, waiting for input:\n")

对于快速而肮脏的线程,我通常求助于子流程命令。 它非常强大,并且与操作系统无关。 它不像线程和队列模块那样提供精细的控制,但是对于程序的外部调用通常做得很好。 注意shell = True必须谨慎使用。

#this can be any command
p1 = subprocess.Popen(["python", "SUBSCRIPTS/TEST.py", "0"], shell=True)

#the thread p1 will run in the background - asynchronously.  If you want to kill it after some time, then you need 

#here do some other tasks/computations
time.sleep(10)

currentStatus = p1.poll()
if currentStatus is None: #then it is still running
  try:
    p1.kill() #maybe try os.kill(p1.pid,2) if p1.kill does not work
  except:
    #do something else if process is done running - maybe do nothing?
    pass

关于阻止另一个Python线程的函数调用的一种可能解释是CPython使用全局解释器锁(GIL)并且阻塞的API调用不会释放它(注意:CPython会在阻塞I / O调用时释放GIL,因此您的raw_input()示例应该可以正常工作)。

如果您无法通过调用bug的API来释放GIL,则可以使用进程而不是线程,例如multiprocessing.Process而不是threading.Thread (API是相同的)。 不同的过程不受GIL的限制。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM