抓住键盘中断以阻止Python多处理工作者在队列中工作 [英] Catch Keyboard Interrupt to stop Python multiprocessing worker from working on queue

查看:508
本文介绍了抓住键盘中断以阻止Python多处理工作者在队列中工作的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



场景



我想要一个多处理器队列,几个工作人员听



如果键盘中断,主进程不应再将新项目放在排队,并在哨兵对象的帮助下,工作人员应优雅地停止。



问题



我使用的当前版本的问题

  signal.signal(signal.SIGINT,signal.SIG_IGN) 

要忽略Ctrl + C,它也被主进程忽略。



任何想法?
我需要使用多处理工作池吗?一些例子表明我可能必须。我可以继续使用队列吗?

 从多进程导入池,进程,队列
import time
进口信号
#http://docs.python.org/3.1/library/multiprocessing.html#multiprocessing.Queue
#http://docs.python.org/3.1/library/multiprocessing.html #multiprocessing.Process


class Worker(Process):
def __init __(self,queue,ident):
super(Worker,self).__ init __()
#忽略信号
signal.signal(signal.SIGINT,signal.SIG_IGN)
self.queue = queue
self.idstr = str(ident)
print Ident+ self.idstr

def run(self):
print'Worker started'
#在这里做一些初始化

print'计算事物$'
为iter(self.queue.get,None)中的数据
print#+ self.idstr +:+ str(data)
time.sleep )
打印#+ self.idstr +队列大小: + str(self.queue.qsize())

打印工作完成

####主要####
request_queue =队列( 10)

在我的范围(4):
工作者(request_queue,i).start()

尝试:
为数据范围(1000000):
request_queue.put(data)
#printQueue Size:+ str(request_queue.qsize())
#Sentinel对象允许清除关闭:每个工作人员1。
在我的范围(4):
request_queue.put(无)

除了KeyboardInterrupt:
打印抓住KeyboardInterrupt,终止工作人员
request_queue.empty()== False:
request_queue.get()
request_queue.put(无)


解决方案

我想我找到了一个解决方案。仍然我不喜欢我从主人那里得到SIGINT 1次,从工人那里得到4次,但也许我必须和他一起生活。


  1. 我为中断信号指定了一个信号处理程序。

  2. 接收到第一个Sig INT后,我忽略更多的SIG Int信号

  3. 我切换停止标志为TRUE

  4. 我打破队列插入循环

  5. 我调用stop函数清除队列并插入停止哨兵

     从多进程导入池,进程,队列
    导入时间
    导入信号
    #http: //docs.python.org/3.1/library/multiprocessing.html#multiprocessing.Queue
    #http://docs.python.org/3.1/library/multiprocessing.html#multiprocessing.Process

    #停止标记循环
    stop = False

    #定义SIGINT
    def signal_handler(sig,frame):
    print'您按Ctrl + C! '
    global stop
    stop = True
    #忽略更多Ctrl + C
    signal.sig nal(signal.SIGINT,signal.SIG_IGN)

    signal.signal(signal.SIGINT,signal_handler)

    def stopSentinel(request_queue):
    printCTRL Stop队列和插入无

    #空现有队列
    而request_queue.empty()== False:
    request_queue.get()

    #一个没有为每个工人
    在我的范围(4):
    request_queue.put(无)


    类工人(进程):
    def __init __(self,queue,ident):
    super(Worker,self).__ init __()

    self.queue = queue
    self.idstr = str(ident)
    printIdent+ self.idstr

    def run(self):
    print'Worker started'
    #在这里做一些初始化

    打印计算事物!
    用于iter中的数据(self.queue.get,None):
    print#+ self.idstr +:+ str(data)
    time .sleep(5)
    打印#+ self.idstr +队列大小:+ s tr(self.queue.qsize())

    打印工作完成



    ####主要#####
    request_queue =队列(10)

    对于范围(4)中的i:
    工作者(request_queue,i).start()

    ### #填充队列与数据####
    范围(1000000)中的数据:
    request_queue.put(data)
    #print队列大小:+ str(request_queue.qsize() )
    #Sentinel对象允许清除关闭:每个工作1。

    #检查止损
    打印检查突破
    如果stop == True:
    打印停止休息
    break

    如果stop == True:
    stopSentinel(request_queue)
    else:
    打印正常停止
    对于范围(4)中的i:
    request_queue。 (无)



From several posts found on stackoverflow i created this code.

Scenario

I want to have a multiprocessing.queue on which several worker "listen"

In case of a keyboard interrupt, the main process should no longer put new items in the queue and with the help of the sentinel objects, the worker should gracefully be stopped.

Problem

My problem with the current version where i use

signal.signal(signal.SIGINT, signal.SIG_IGN) 

To ignore the Ctrl + C is that it is also ignored by the main process.

Any Ideas ? Do I need to use the multiprocessing worker pool ? Some examples indicate that i might have to. Can I then still use the queue ?

from multiprocessing import Pool, Process,Queue
import time
import signal
# http://docs.python.org/3.1/library/multiprocessing.html#multiprocessing.Queue
# http://docs.python.org/3.1/library/multiprocessing.html#multiprocessing.Process


class Worker(Process):
    def __init__(self, queue,ident):
        super(Worker, self).__init__()
        # Ignore Signals
        signal.signal(signal.SIGINT, signal.SIG_IGN)
        self.queue= queue
        self.idstr= str(ident)
        print "Ident" + self.idstr

    def run(self):
        print 'Worker started'
        # do some initialization here

        print 'Computing things!'
        for data in iter( self.queue.get, None ):
            print "#" + self.idstr + " : " + str(data)
            time.sleep(5)
            print "#" + self.idstr + "Queue Size: " + str(self.queue.qsize())

        print "Worker Done"

#### Main ####
request_queue = Queue(10)

for i in range(4):
    Worker( request_queue,i ).start()

try:
    for data in range(1000000):
        request_queue.put( data )
        #print "Queue Size: " + str(request_queue.qsize())
        # Sentinel objects to allow clean shutdown: 1 per worker.
    for i in range(4):
        request_queue.put( None ) 

except KeyboardInterrupt:
    print "Caught KeyboardInterrupt, terminating workers"
    while  request_queue.empty()==False:
         request_queue.get()
    request_queue.put( None )    

解决方案

I think I found a solution. Still I don't like that I get the SIGINT 1 time from main and 4 times from the Worker, but maybe I have to live with that.

  1. I specified a signal handler for the Interrupt Signal.
  2. After Receiving the first Sig INT I ignore more SIG Int signal
  3. I switch the stop flag to TRUE
  4. I break out the queue insert loop
  5. I call stop function which clears the queue and inserts the stop sentinels

    from multiprocessing import Pool, Process,Queue
    import time
    import signal
    # http://docs.python.org/3.1/library/multiprocessing.html#multiprocessing.Queue
    # http://docs.python.org/3.1/library/multiprocessing.html#multiprocessing.Process
    
    # Stop Flag for loop
    stop = False
    
    # Define SIGINT
    def signal_handler(sig, frame):
        print 'You pressed Ctrl+C!'
        global stop
        stop = True
        # Ignore more Ctrl+C
        signal.signal(signal.SIGINT, signal.SIG_IGN) 
    
    signal.signal(signal.SIGINT, signal_handler)
    
    def stopSentinel(request_queue):
        print "CTRL Stop Queue and insert None"
    
    # Empty Existing Queue
    while  request_queue.empty()==False:
         request_queue.get()
    
    # Put One None for each Worker
    for i in range(4):
        request_queue.put( None ) 
    
    
    class Worker(Process):
        def __init__(self, queue,ident):
            super(Worker, self).__init__()
    
            self.queue= queue
            self.idstr= str(ident)
            print "Ident" + self.idstr
    
        def run(self):
            print 'Worker started'
            # do some initialization here
    
            print 'Computing things!'
            for data in iter( self.queue.get, None ):
                print "#" + self.idstr + " : " + str(data)
                time.sleep(5)
                print "#" + self.idstr + "Queue Size: " + str(self.queue.qsize())
    
            print "Worker Done"
    
    
    
    #### Main #####
    request_queue = Queue(10)
    
    for i in range(4):
        Worker( request_queue,i ).start()
    
    #### Fill Queue with Data ####
    for data in range(1000000):
        request_queue.put( data )
        #print "Queue Size: " + str(request_queue.qsize())
        # Sentinel objects to allow clean shutdown: 1 per worker.
    
        # Check for Stop
        print "Check Breakout"
        if stop == True:
            print "Stop Break"
            break
    
    if stop == True:
        stopSentinel(request_queue)
    else:       
        print "Normal Stop" 
        for i in range(4):
            request_queue.put( None ) 
    

这篇关于抓住键盘中断以阻止Python多处理工作者在队列中工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆