【问题标题】:Inconsistent behavior when attempting to terminate python subprocess running on a thread尝试终止在线程上运行的 python 子进程时的行为不一致
【发布时间】:2013-03-06 07:07:15
【问题描述】:

当我试图终止一个运行在单独线程上的长时间运行的进程时,我遇到了问题。

以下是程序。 WorkOne 创建一个子进程并运行一个长时间运行的进程“adb logcat”,该进程会生成日志行。我在 main() 中启动 WorkOne,等待 5 秒并尝试停止它。多次运行给出多个输出

import threading
import time
import subprocess
import sys

class WorkOne(threading.Thread):

    def __init__(self):
        threading.Thread.__init__(self)
        self.event = threading.Event()  
        self.process = subprocess.Popen(['adb','logcat'], stdout=subprocess.PIPE, stderr=sys.stdout.fileno())      

    def run(self):   
        for line in iter(self.process.stdout.readline,''):            
            #print line
            if self.event.is_set():
                self.process.terminate()
                self.process.kill()
                break;
        print 'exited For'

    def stop(self):
        self.event.set()

def main():

    print 'starting worker1'
    worker1 = WorkOne()
    worker1.start()
    print 'number of threads: ' + str(threading.active_count())
    time.sleep(5)
    worker1.stop()
    worker1.join(5)
    print 'number of threads: ' + str(threading.active_count())

if __name__ == '__main__':
    main()

有时我会得到 [A]:

starting worker1
number of threads: 2
number of threads: 2
exited For

有时我会得到 [B]:

starting worker1
number of threads: 2
number of threads: 1
exited For

有时我会得到 [C]:

starting worker1
number of threads: 2
number of threads: 2

我想我应该一直期望得到 [B]。这里出了什么问题?

【问题讨论】:

  • 由于您在join() 调用中设置了超时,因此即使线程已停止,它也可能保持活动状态(例如,它正在等待for 循环中的新行) .
  • 看起来这就是问题所在,将终止和终止调用从 for 循环中移至停止方法,现在我得到了我期望的一致输出

标签: python multithreading subprocess terminate long-running-processes


【解决方案1】:

我认为 [B] 只有在子进程花费不到 10 秒的情况下才有可能:主线程休眠 5 秒,然后 workerjoin() 的 5 秒超时内完成。

在 10 秒或更长时间内,worker 即使在调用 join() 之后也可以存活,因为它有一个超时参数,这可能发生也可能不会发生。然后你可以得到 [A](子进程几秒钟后完成)或 [C](子进程更晚完成)。

要始终获得 [B],请删除 join() 的超时参数,以便主线程等待 worker 完成(或通过将 kill 调用置于循环之外确保在 10 秒内终止进程)。

【讨论】:

    【解决方案2】:

    改变

           if self.event.is_set():
                self.process.terminate()
                self.process.kill()
                break;
    

            if self.event.is_set():
                self.process.terminate()
                self.process.wait()
                break
    

    分号说明这里有问题。

    我猜如果没有wait(),线程有时会过早解除对work1.join(5) 的阻塞。在这些情况下,threading.active_count() 返回 2。

    而且,正如@A.Rodas 所说,work1.join(5) 应该是 work1.join(),以确保在完成 work1 之前连接不会解除阻塞。


    顺便说一句,我不知道你为什么要接连打电话给terminate 然后kill。在 Unix 上,kill 是一种更严格的终止形式。在 Windows 上,它们是相同的。所以如果你要调用kill,就不需要调用terminate。

    既然你知道subprocess调用的程序,你也应该知道终止是否足以停止它。

    因此,您应该只需要一个:self.process.terminate()self.process.kill()

    【讨论】:

      猜你喜欢
      • 2013-05-12
      • 2017-04-21
      • 2023-03-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-08
      • 2019-05-08
      • 2015-10-18
      相关资源
      最近更新 更多