Python-通知子进程上被阻止的另一个线程



我正在linux上用python 3.4创建一个带有web前端的自定义作业调度程序。该程序创建一个守护进程(使用者)线程,等待PriorityQueue中的作业可用。可以通过将这些作业添加到队列的web界面手动添加这些作业。当使用者线程找到一个作业时,它会使用subprocess.run执行一个程序,并等待它完成。

工作线程的基本思想:

class Worker(threading.Thread):
def __init__(self, queue):
    self.queue = queue
    # more code here
def run(self):
    while True:
        try:
            job = self.queue.get()
            #do some work
            proc = subprocess.run("myprogram", timeout=my_timeout)
            #do some more things
        except TimeoutExpired:
            #do some administration
            self.queue.add(job)

但是:

  • 这个使用者应该能够从前端(主线程)接收到某种信号,即它应该停止当前作业,转而处理队列中的下一个作业(保存当前作业的状态并将其再次添加到队列的末尾)。在subprocess.run()上被阻止时,这种情况可能(而且很可能)发生
  • 可以简单地终止子进程(执行的程序将sme状态保存在文件中),但工作线程需要对终止的作业进行一些管理,以确保以后可以恢复
  • 可以有多个这样的工作线程
  • 信号处理程序不是一个选项(因为它们总是由作为Web服务器的主线程处理,不应该为此而烦恼)
  • 在这种情况下,进程主动轮询事件(如子进程退出、超时发生或中断事件)的事件循环并不是一个真正的解决方案,而是一个丑陋的破解。这些作业的性能很重,不需要不断切换上下文

我应该使用什么同步原语来中断这个线程,或者确保它以阻塞的方式同时等待几个事件?

我认为您无意中掩盖了一个简单的解决方案:您的第二个要点说您有能力杀死在子流程中运行的程序。请注意,subprocess.call返回子流程的返回代码。这意味着您可以让主线程终止子进程,只需检查返回代码,看看是否需要进行任何清理。更好的是,您可以使用subprocess.check_call,如果返回代码不是0,它将为您引发异常。我不知道你在哪个平台上工作,但在Linux上,被杀死的进程如果被杀死,通常不会返回0。

它可能看起来像这样:

class Worker(threading.Thread):
def __init__(self, queue):
    self.queue = queue
    # more code here
def run(self):
    while True:
        try:
            job = self.queue.get()
            #do some work
            subprocess.check_call("myprogram", timeout=my_timeout)
            #do some more things
        except (TimeoutExpired, subprocess.CalledProcessError):
            #do some administration
            self.queue.add(job)

请注意,如果使用的是Python 3.5,则可以使用subprocess.run,并将check参数设置为True

如果您强烈需要处理当不运行子进程时需要中断工作程序的情况,那么我认为您将不得不使用轮询循环,因为我认为Python中的线程不支持您所寻找的行为。您可以使用线程。事件对象将"立即停止工作"伪信号从主线程传递给工作线程,并让工作线程定期检查该事件对象的状态。

如果您愿意考虑使用多处理而不是线程,请考虑切换到多处理模块,这将允许您处理信号。生成全面的子进程而不是线程会带来更多的开销,但您本质上是在寻找类似信号的异步行为,我认为Python的线程库不支持这样的行为。不过,一个好处是,您可以从全局解释器锁(PDF链接)中解放出来,因此,如果您的工作进程(以前的线程)正在做任何CPU密集型的事情,您实际上可能会看到一些速度优势。

最新更新