【问题标题】:Killing a script launched in a Process via os.system()通过 os.system() 杀死在进程中启动的脚本
【发布时间】:2012-09-01 12:18:21
【问题描述】:

我有一个启动多个进程的 python 脚本。每个进程基本上只是调用一个shell脚本:

from multiprocessing import Process
import os
import logging

def thread_method(n = 4):
    global logger
    command = "~/Scripts/run.sh " + str(n) + " >> /var/log/mylog.log"
    if (debug): logger.debug(command)
    os.system(command)

我启动了几个这样的线程,它们旨在在后台运行。我想在这些线程上设置一个超时,这样如果超过超时,它们就会被杀死:

t = []
for x in range(10):
    try:
        t.append(Process(target=thread_method, args=(x,) ) )
        t[-1].start()
    except Exception as e:
        logger.error("Error: unable to start thread")
        logger.error("Error message: " + str(e))
logger.info("Waiting up to 60 seconds to allow threads to finish")
t[0].join(60)
for n in range(len(t)):
    if t[n].is_alive():
    logger.info(str(n) + " is still alive after 60 seconds, forcibly terminating")
     t[n].terminate()

问题是在进程线程上调用 terminate() 并不会终止启动的 run.sh 脚本 - 它会继续在后台运行,直到我从命令行强制终止它,或者它在内部完成。有没有办法终止也杀死由 os.system() 创建的子shell?

【问题讨论】:

    标签: python process os.system


    【解决方案1】:

    你应该使用一个事件来通知worker终止,用subprocess模块运行子进程,然后用Popen.terminate()终止它。调用 Process.terminate() 将不允许它的工作人员进行清理。见the documentation for Process.terminate()

    【讨论】:

    • 你混淆了 subprocess.Popen.terminate 和 multiprocessing.Process.terminate
    • @J.F.Sebastian 但是multiprocessing.Process.terminate() 不允许它控制的进程进行清理。我的意思是使用一个事件来终止multiprocessing 的工作人员,以便它可以清理并在工作人员控制的子进程上调用subprocess.Popen.terminate()
    • 你是对的。我刚刚忽略了这部分问题,因为the answer doesn't require neither threads (threading) nor processes (multiprocessing).
    【解决方案2】:

    改用subprocess,它的对象有一个明确的terminate() method

    【讨论】:

      【解决方案3】:

      在 Python 3.3 中,子进程模块支持超时:http://docs.python.org/dev/library/subprocess.html

      有关 Python 2.x 的其他解决方案,请查看此线程:Using module 'subprocess' with timeout

      【讨论】:

        【解决方案4】:

        基于Stop reading process output in Python without hang?:

        import os
        import time
        from subprocess import Popen
        
        def start_process(n, stdout):
            # no need for `global logger` you don't assign to it
            command = [os.path.expanduser("~/Scripts/run.sh"), str(n)]
            logger.debug(command) # no need for if(debug); set logging level instead
            return Popen(command, stdout=stdout) # run directly
        
        # no need to use threads; Popen is asynchronous 
        with open('/tmp/scripts_output.txt') as file:
            processes = [start_process(i, file) for i in range(10)]
        
            # wait at most timeout seconds for the processes to complete
            # you could use p.wait() and signal.alarm or threading.Timer instead
            endtime = time.time() + timeout
            while any(p.poll() is None for p in processes) and time.time() < endtime:
                time.sleep(.04)
        
            # terminate unfinished processes
            for p in processes:
                if p.poll() is None:
                    p.terminate()
                    p.wait() # blocks if `kill pid` is ignored
        

        如果可用,请使用p.wait(timeout)

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-11-11
          • 1970-01-01
          • 1970-01-01
          • 2022-11-11
          • 2020-01-18
          • 2017-08-04
          • 2022-10-21
          • 2010-12-23
          相关资源
          最近更新 更多