2017-06-16 80 views
0

如果執行鍵盤快捷鍵CTRL+C,我希望客戶和生產者進程在下面的python腳本中停止。但進程不會停止 - 鍵盤中斷不會傳遞給它們。此外,主進程的except塊不會被輸入。Python多處理:使用KeyboardInterrupt殺死生產者和消費者進程

import time 
import multiprocessing as mp 
from multiprocessing.managers import SyncManager 
import signal 

class Consumer(mp.Process): 
    def __init__(self, **kwargs): 
     mp.Process.__init__(self, **kwargs) 

    def run(self): 
     proc_name = self.name 
     try: 
      while True: 
       print("{}".format(proc_name)) 
       time.sleep(3) 
     except KeyboardInterrupt: 
      print("{} stopped".format(proc_name)) # never printed 
     return 

class Producer(mp.Process): 
    def __init__(self, **kwargs): 
     mp.Process.__init__(self, **kwargs) 

    def run(self): 
     try: 
      while True: 
       time.sleep(3) 
       print("Producer here.") 
     except KeyboardInterrupt: 
      print("Producer stopped.") # never printed 
     return 

def main(): 
    def __init_worker(): 
     signal.signal(signal.SIGINT, signal.SIG_IGN) 
     print('init') # not printed!!?? 

# manager = SyncManager() # does not change anything 
# manager.start(__init_worker) 

    consumers = [Consumer(target=__init_worker) for i in xrange(3)] 
    producer = Producer(target=__init_worker) 

    producer.daemon = True # does not change anything 
    producer.start() 
    for c in consumers: 
     c.daemon = True 
     c.start() 

    try: 
     producer.join() 
     for c in consumers: 
      c.join() 
    except Exception as e: 
     print('STOP') # never printed 
     raise e 

if __name__ == '__main__': 
    main() 

有可能也爲我的任務的解決方案通過使用multiprocesing.Pool爲客戶和讓主流程工作作爲製片人,但我想知道爲什麼我的實現不工作,因爲它的目的是什麼我需要調整。

我意識到__init_worker似乎沒有執行(如果它位於main之外,則沒有區別)。也許沒有將KeyboardInterrupt傳遞給客戶和生產者流程的原因是什麼?

+0

您正在重寫'run',這是調用進程'_target'屬性的方法。所以'__init_worker'肯定不會被執行。 – eryksun

+0

爲了便於解釋。是否有可能將我的函數'run'的內容傳遞給super'run'?只是調用'super.run()'不起作用,我假設。 – AnnetteC

+0

它是'super(Producer,self).run()',等等。在Python 3中,您可以使用不帶參數的'super()'。默認的Process.run調用對象的_target(如果有的話)並返回。但通常,執行'run'的'threading.Thread'或'multiprocessing.Process'子類不會使用'target'參數。 – eryksun

回答

1

基於eryksun的評論,我改進了我的代碼,現在使用multiprocessing.Event。現在腳本正在按照預期工作。我也刪除了一些我認爲不再需要的行。由於我在網上搜索時,沒有發現任何類似的解決方案,在這裏我的代碼來:

import time 
import multiprocessing as mp 

class Consumer(mp.Process): 
    def __init__(self, quit_event, **kwargs): 
     mp.Process.__init__(self, **kwargs) 
     self.quit_event = quit_event 

    def run(self): 
     proc_name = self.name 
     while not self.quit_event.is_set(): 
      print("{}".format(proc_name)) 
      time.sleep(3) 
     print("{} stopped".format(proc_name)) 
     return 

class Producer(mp.Process): 
    def __init__(self, quit_event, **kwargs): 
     mp.Process.__init__(self, **kwargs) 
     self.quit_event = quit_event 

    def run(self): 
     while not self.quit_event.is_set(): 
      print("Producer here.") 
      time.sleep(3) 
     print("Producer stopped") 
     return 


def main(): 
    quit_event = mp.Event() 

    consumers = [Consumer(quit_event) for i in xrange(3)] 
    producer = Producer(quit_event) 

    producer.start() 
    for c in consumers: 
     c.start() 

    try: 
     producer.join() 
     for c in consumers: 
      c.join() 
    except KeyboardInterrupt as e: 
     print('\nSTOP') 
     quit_event.set() 
    except Exception as e: 
     quit_event.set() 
     raise e 
    finally: 
     producer.terminate() 
     producer.join() 
     for c in consumers: 
      c.terminate() 
      c.join() 

if __name__ == '__main__': 
    main() 

希望能,它可以幫助別人。

編輯:交換terminatejoin陳述。