簡體   English   中英

從具有無限循環和終止的子進程中隨機調用

[英]Callback at random times from a child process with infinite loop, and termination

我需要在主流程中對子流程中發生的隨機事件做出反應。 我已經在主進程和子進程之間建立了一個隊列,並在主進程的輔助線程中運行了一個“隊列輪詢器”,並在每次在隊列中找到一個項目時調用一個回調函數。 該代碼在下面,似乎可以正常工作。 問題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
...

一般觀察:

類MyChildProcess

您無需為子進程和偵聽器線程創建單獨的類。 簡單的功能可以工作。

pollQueue

您可以在偵聽器線程中使用阻塞的get()調用。 這將使該線程更有效率。

關機

您可以使用信號殺死進程,但是殺死線程更困難(實際上是不可能的)。 關閉例程將取決於您如何處理仍在隊列中的項目。

如果您不在乎關閉時處理隊列中剩余的項目,則只需向子進程發送TERM信號並退出主線程即可。 由於偵聽器線程的.daemon屬性設置為True,因此它也將退出。

如果您確實關心在關閉時處理隊列中的項目,則應通過發送特殊的哨兵值,然后加入該線程以等待其退出來通知偵聽器線程退出其處理循環。

這是一個結合了以上想法的示例。 None選擇“ 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()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM