Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/310.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 线程被阻塞调用阻塞-如何在阻塞调用上超时?_Python_Multithreading_Timeout_Blocking - Fatal编程技术网

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

Python 线程被阻塞调用阻塞-如何在阻塞调用上超时?,python,multithreading,timeout,blocking,Python,Multithreading,Timeout,Blocking,我有一个python程序,它运行一个外部程序并启动一个超时线程。超时线程应该倒计时10分钟,如果操作外部程序的脚本没有在这段时间内完成,它应该杀死外部程序 我的线程乍一看似乎运行良好,我的主脚本和线程同时运行,没有任何问题。但是如果在外部程序中出现一个弹出窗口,它会停止我的脚本,甚至倒计时线程也会停止计数,因此它的工作完全失败 我假设问题是脚本在API中为外部程序调用了一个阻塞函数,该函数被弹出窗口阻塞。我理解它为什么会阻止我的主程序,但不理解它为什么会阻止我的倒计时线程。因此,一个可能的解决方

我有一个python程序,它运行一个外部程序并启动一个超时线程。超时线程应该倒计时10分钟,如果操作外部程序的脚本没有在这段时间内完成,它应该杀死外部程序

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

我假设问题是脚本在API中为外部程序调用了一个阻塞函数,该函数被弹出窗口阻塞。我理解它为什么会阻止我的主程序,但不理解它为什么会阻止我的倒计时线程。因此,一个可能的解决方案可能是为倒计时运行一个单独的脚本,但我希望尽可能保持它的整洁,并且为此启动一个脚本似乎非常混乱

我到处寻找线索,但没找到多少。此处有对gevent库的引用: ,但这似乎是一项基本任务,我不想为此包含外部库

我还找到了一个使用windows多媒体定时器的解决方案,但我以前从未使用过这个,而且我担心代码不能灵活使用它。脚本仅适用于Windows,但它应该可以在XP上的所有Windows上运行

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

关于如何以最简单的方式处理此问题,您有什么想法吗

这是我正在创建的简化线程(在空闲状态下运行以再现问题):


对于快速而脏的线程,我通常求助于子进程命令。它非常健壮,并且与操作系统无关。它不像线程和队列模块那样提供细粒度的控制,但是对于程序的外部调用,它通常做得很好。注意:必须谨慎使用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\u input()
示例应该按原样工作)


如果您不能调用buggy API来释放GIL,那么您可以使用进程而不是线程,例如,而不是
threading.thread
(API是相同的)。不同的过程不受GIL的限制。

请给我们一些(希望是)小而完整的代码示例来说明问题,帮助我们重现问题。您如何“操作”外部程序(调用阻塞函数)?我在示例中添加了一个示例阻塞调用。这个问题现在可以重现了。我希望我的计时器线程在等待输入时继续计数。正如我注意到的,原始输入只在IDE中阻塞,如果您正常运行它,则不会阻塞。因此,为了这个示例,请在空闲状态下运行它。这不是一个很大的bug,但是在您的代码中,您使用了
self.countdown
来表示不同时间的两件不同的事情。在运行
startCountdown
之前,它是一个方法,之后是一个线程实例。您可能应该为其中一个用途选择不同的名称。不过,它不会改变什么,因为您只使用该方法作为线程的目标,而且在那一点上它仍然可用。目前,我正在使用与您的示例类似的子流程,尽管我希望可以避免它。我可以问一下为什么在你的样本中需要shell=True吗?@Anja,shell=True不是必需的。我经常死记硬背。除子进程外,您始终可以使用线程或队列模块。除非您希望将其他参数传递给shell,否则将
shell=True
与列表参数一起使用是不正确的(它只是在POSIX系统上失败,因为它相当于)。是的,我尝试使用线程,但我的超时线程被阻止,停止计数。您是否理解为什么我的示例中的超时线程在主程序到达阻塞调用时停止?我想知道为什么我的尝试失败了,这就解释了问题。到目前为止,我已经有了子流程模块的解决方案,但在处理多个流程时,多处理似乎更好。谢谢你的主意@AnjaV.:如果这确实是一个问题,那么正确的解决方案是修复上游API,以便外部程序在调用阻塞系统调用时释放GIL<代码>多处理。过程只是一种变通方法。
#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