[英]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.