从具有无限循环和终止的子进程随机回调

时间:2016-07-24 18:10:16

标签: python multithreading multiprocessing

我需要在主过程中对子进程中发生的随机事件做出反应。我用main和子进程之间的队列实现了这个,并且在主进程的辅助线程中运行了一个'queue poller',每次在队列中找到一个项目时都调用一个回调函数。代码在下面,似乎工作。 问题1:您能否告诉我策略是否正确或是否存在更简单的问题? 问题2:我试图在停止主循环时终止子进程和辅助线程,但它失败了,至少在spyder中失败了。我该怎么做才能正确终止一切? 谢谢你的帮助: - )

from threading import Thread
from multiprocessing import Process, Queue
from time import sleep
from random import random

class MyChildProcess(Process):
    """
    This process runs as a child process of the main process.
    It fills a queue (instantiated in the main process - main thread) at random times.
    """
    def __init__(self,queue):
        super(MyChildProcess,self).__init__()
        self._q = queue             # memorizes the queue
        self._i = 0                 # attribute to be incremented and put in the queue

    def run(self):
        while True:
            self._q.put(self._i)    # puts in the queue
            self._i += 1            # increment for next time
            sleep(random())         # wait between 0 and 1s

class myListenerInSeparateThreadOfMainProcess():
    """
    This listener runs in a secondary thread of the main process.
    It polls a queue and calls back a function for each item found.
    """
    def __init__(self, queue, callbackFunction):
        self._q = queue              # memorizes the queue
        self._cbf = callbackFunction # memorizes the queue
        self.pollQueue()

    def pollQueue(self):
        while True:
            sleep(0.2)               # polls 5 times a second max
            self.readQueue()   

    def readQueue(self):
        while not self._q.empty():   # empties the queue each time
            self._cbf(self._q.get()) # calls the callback function for each item

def runListener(q,cbf):
    """Target function for the secondary thread"""
    myListenerInSeparateThreadOfMainProcess(q,cbf)    

def callBackFunc(*args):
    """This is my reacting function"""
    print 'Main process gets data from queue: ', args

if __name__ == '__main__':     
    q= Queue()
    t = Thread(target=runListener, args=(q,callBackFunc))
    t.daemon=True        # try to have the secondary thread terminated if main thread terminates
    t.start()
    p = MyChildProcess(q)
    p.daemon = True      # try to have the child process terminated if parent process terminates
    p.start()            # no target scheme and no parent blocking by join
    while True:          # this is the main application loop
        sleep(2)
        print 'In main loop doing something independant from the rest'  

这是我得到的:

Main process gets data from queue:  (0,)
Main process gets data from queue:  (1,)
Main process gets data from queue:  (2,)
Main process gets data from queue:  (3,)
In main loop doing something independant from queue management
Main process gets data from queue:  (4,)
Main process gets data from queue:  (5,)
Main process gets data from queue:  (6,)
Main process gets data from queue:  (7,)
In main loop doing something independant from queue management
Main process gets data from queue:  (8,)
Main process gets data from queue:  (9,)
In main loop doing something independant from queue management
...

1 个答案:

答案 0 :(得分:0)

一般观察:

类MyChildProcess

您不需要为子进程和侦听器线程创建单独的类。简单的功能可以工作。

<强> pollQueue

您可以在侦听器线程中使用阻塞get()调用。这将使该线程更有效。

关闭

你可以用一个信号杀死一个进程,但杀死一个线程更难(真的不可能)。你的关机 例程将取决于您希望如何处理仍在队列中的项目。

如果您不关心在关闭时处理队列中剩余的项目,您可以 只需向子进程发送一个TERM信号并退出主线程。自从听众 线程将.daemon属性设置为True,它也将退出。

如果你关心在关机时处理队列中的项目,你应该这样做 通过发送特殊的 sentinel 值通知侦听器线程退出其处理循环 然后加入该线程等待它退出。

这是一个包含上述想法的例子。我没有选择None 哨兵价值。

#!/usr/bin/env python

from threading import Thread
from multiprocessing import Process, Queue
from time import sleep
from random import random
import os
import signal

def child_process(q):
  i = 1
  while True:
    q.put(i)
    i += 1
    sleep( random() )

def listener_thread(q, callback):
  while True:
    item = q.get()   # this will block until an item is ready
    if item is None:
      break
    callback(item)

def doit(item):
  print "got:", item

def main():
  q = Queue()

  # start up the child process:
  child = Process(target=child_process, args=(q,))
  child.start()

  # start up the listener
  listener = Thread(target=listener_thread, args=(q,doit))
  listener.daemon = True
  listener.start()

  sleep(5)
  print "Exiting"
  os.kill( child.pid, signal.SIGTERM )
  q.put(None)
  listener.join()

main()