2015-08-22 62 views
2

中斷我發現this文章中介紹如何殺死使用CTR + C運行多碼。以下代碼是完全工作(它可以使用CTRL + C被終止的話):鍵盤與Python的多處理池和地圖功能

#!/usr/bin/env python 

# Copyright (c) 2011 John Reese 
# Licensed under the MIT License 

import multiprocessing 
import os 
import signal 
import time 

def init_worker(): 
    signal.signal(signal.SIGINT, signal.SIG_IGN) 

def run_worker(): 
    time.sleep(15) 

def main(): 
    print "Initializng 5 workers" 
    pool = multiprocessing.Pool(5, init_worker) 

    print "Starting 3 jobs of 15 seconds each" 
    for i in range(3): 
     pool.apply_async(run_worker) 

    try: 
     print "Waiting 10 seconds" 
     time.sleep(10) 

    except KeyboardInterrupt: 
     print "Caught KeyboardInterrupt, terminating workers" 
     pool.terminate() 
     pool.join() 

    else: 
     print "Quitting normally" 
     pool.close() 
     pool.join() 

if __name__ == "__main__": 
    main() 

的問題是,我使用不同的函數從多處理模塊。我不知道它們與以前的方法有什麼不同,它只適用於我(除了這個例子不能用ctrl + c來終止它)。這是我一直在努力根據以上的版本進行修改(不包括信號以前的版本處理用於印刷回溯當CTRL + C被擊中)代碼:

#!/usr/bin/env python 

from time import sleep 
import signal 
from multiprocessing import Pool 
from multiprocessing import cpu_count 

def init_worker(n): 
    signal.signal(signal.SIGINT, signal.SIG_IGN) 
    sleep(.5) 
    print "n = %d" % n 
    results_sent_back_to_parent = n * n 
    return results_sent_back_to_parent 

if __name__ == '__main__': 
    try: 
    p = Pool(processes = cpu_count()) 
    results = p.map(init_worker, range(50), chunksize = 10) 
    except KeyboardInterrupt: 
    pool.terminate() 
    pool.join() 

    print(results) 

問題:

  1. 爲什麼CTRL + C在第一個例子中工作,但不是在第二
  2. 如何修改第二個代碼,CTRL + C是否行得通呢?
  3. 如何既代碼不同(我的意思是在多的情況下,一個使用例如pool.apply_async和另一map)?

編輯

在回覆@ user2386841

我在init_worker評論signal.signal(signal.SIGINT, signal.SIG_IGN)並試圖if __name__ == '__main__':後添加正確的,但是當我增加一條,作爲最後一個ID沒有工作,同在try:塊行

在答覆@ThomasWagenaar

它的行爲完全相同(我也嘗試了上述信號處理器的各個位置);儘管打ctr+c和唯一可能的方式殺死腳本數字印刷是使用ctrl+z,然後用kill %1

+0

嗯,不知道關於這一點,但我注意到,在主進程的第一段代碼中有十秒鐘的時間,這會讓您停止進程的oppurtunity。如果在結果= 10秒後添加10秒的time.sleep會發生什麼?在主進程中的第二段代碼中,然後按ctrl + c幾次?讓我知道如果我是對/錯! –

+0

可能重複[鍵盤中斷與python的多處理池](https://stackoverflow.com/questions/1408356/keyboard-interrupts-with-pythons-multiprocessing-pool) – tabata

回答

1

舊線殺將其發送到後臺,但這些例子表現不同的原因是由於衆所周知的Python的bug (http://bugs.python.org/issue8296,在this StackOverflow answer中也有解釋)。

您應該完整閱讀其他答案以獲得完整的想法,但總之問題在於底層threading.Condition.wait()調用的行爲有所不同,具體取決於它是否通過超時。 map()不使用超時,但顯然apply_async()不利用這個超時參數,並且僅當底層wait()通話有超時它正確地中斷。

你應該能夠重構你的代碼使用的the Pool docs指定的異步方法之一。

1

我解決了這個問題,這個簡單的功能:

import os 
import psutil 
import signal 

parent_id = os.getpid() 
def worker_init(): 
    def sig_int(signal_num, frame): 
     print('signal: %s' % signal_num) 
     parent = psutil.Process(parent_id) 
     for child in parent.children(): 
      if child.pid != os.getpid(): 
       print("killing child: %s" % child.pid) 
       child.kill() 
     print("killing parent: %s" % parent_id) 
     parent.kill() 
     print("suicide: %s" % os.getpid()) 
     psutil.Process(os.getpid()).kill() 
    signal.signal(signal.SIGINT, sig_int) 

我連接到我的游泳池:

Pool(3, worker_init) 

後CTRL^C的結果是:

^Csignal: 2 
signal: 2 
signal: 2 
killing child: 14109 
killing child: 14110 
killing parent: 14104 
suicide: 14108 
Killed 

而且一切都會退出