[英]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.