简体   繁体   English

如何中断/停止/结束挂起的多线程python程序

[英]How to Interrupt/Stop/End a hanging multi-threaded python program

I have a python program that implements threads like this: 我有一个实现以下线程的python程序:

   class Mythread(threading.Thread):
        def __init__(self, name, q):
            threading.Thread.__init__(self)
            self.name = name
            self.q = q

        def run(self):
            print "Starting %s..." % (self.name)
            while True:
                ## Get data from queue
                data = self.q.get()
                ## do_some_processing with data ###
                process_data(data)
                ## Mark Queue item as done
                self.q.task_done()
            print "Exiting %s..." % (self.name)


    def call_threaded_program():
        ##Setup the threads. Define threads,queue,locks 
        threads = []    
        q = Queue.Queue()
        thread_count = n #some number
        data_list = [] #some data list containing data

        ##Create Threads
        for thread_id in range(1, thread_count+1):
            thread_name = "Thread-" + str(thread_id)
            thread = Mythread(thread_name,q)
            thread.daemon = True
            thread.start()

        ##Fill data in Queue
        for data_item in data_list:
            q.put(data_item)

        try:
            ##Wait for queue to be exhausted and then exit main program
            q.join()
        except (KeyboardInterrupt, SystemExit) as e:
            print "Interrupt Issued. Exiting Program with error state: %s"%(str(e))
            exit(1)

The call_threaded_program() is called from a different program. 从另一个程序调用call_threaded_program()。

I have the code working under normal circumstances. 我的代码在正常情况下可以工作。 However if an error/exception occurs in one of the threads, then the program is stuck (as the queue join is infinitely blocking). 但是,如果其中一个线程发生错误/异常,则程序将被卡住(因为队列联接无限地阻塞)。 The only way I am able to quit this program is to close the terminal itself. 我能够退出此程序的唯一方法是关闭终端本身。

What is the best way to terminate this program when a thread bails out? 当线程出故障时终止该程序的最佳方法是什么? Is there a clean (actually I would take any way) way of doing this? 是否有一种干净的方法(实际上我会采取任何方式)? I know this question has been asked numerous times, but I am still unable to find a convincing answer. 我知道这个问题已被问过无数次,但我仍然找不到令人信服的答案。 I would really appreciate any help. 我真的很感谢您的帮助。

EDIT: I tried removing the join on the queue and used a global exit flag as suggested in Is there any way to kill a Thread in Python? 编辑:我尝试删除队列上的联接,并使用“ 是否有任何方法可以杀死Python中的线程?”中的建议使用全局退出标志 However, Now the behavior is so strange, I can't comprehend what is going on. 但是,现在的行为是如此奇怪,我无法理解发生了什么。

    import threading
    import Queue
    import time

    exit_flag = False

    class Mythread (threading.Thread):
        def __init__(self,name,q):
            threading.Thread.__init__(self)
            self.name = name
            self.q = q

        def run(self):
            try:    
                # Start Thread
                print "Starting %s...."%(self.name)
                # Do Some Processing
                while not exit_flag:
                    data = self.q.get()
                    print "%s processing %s"%(self.name,str(data))
                    self.q.task_done()
                # Exit thread
                print "Exiting %s..."%(self.name)
            except Exception as e:
                print "Exiting %s due to Error: %s"%(self.name,str(e))


    def main():
        global exit_flag

        ##Setup the threads. Define threads,queue,locks 
        threads = []    
        q = Queue.Queue()
        thread_count = 20
        data_list = range(1,50)

        ##Create Threads
        for thread_id in range(1,thread_count+1):
            thread_name = "Thread-" + str(thread_id)
            thread = Mythread(thread_name,q)
            thread.daemon = True
            threads.append(thread)
            thread.start()

        ##Fill data in Queue
        for data_item in data_list:
          q.put(data_item)


        try:
          ##Wait for queue to be exhausted and then exit main program
          while not q.empty():
            pass

          # Stop the threads
          exit_flag = True

          # Wait for threads to finish
          print "Waiting for threads to finish..."
          while threading.activeCount() > 1:
            print "Active Threads:",threading.activeCount()
            time.sleep(1)
            pass

          print "Finished Successfully"
        except (KeyboardInterrupt, SystemExit) as e:
          print "Interrupt Issued. Exiting Program with error state: %s"%(str(e))


     if __name__ == '__main__':
         main()

The program's output is as below: 该程序的输出如下:

    #Threads get started correctly
    #The output also is getting processed but then towards the end, All i see are
    Active Threads: 16
    Active Threads: 16
    Active Threads: 16...

The program then just hangs or keeps on printing the active threads. 然后,该程序只是挂起或继续打印活动线程。 However since the exit flag is set to True, the thread's run method is not being exercised. 但是,由于将退出标志设置为True,因此不会执行线程的run方法。 So I have no clue as to how these threads are kept up or what is happening. 因此,对于这些线程如何保持运行或发生什么情况,我一无所知。

EDIT : I found the problem. 编辑 :我发现了问题。 In the above code, thread's get method were blocking and hence unable to quit. 在上面的代码中,线程的get方法被阻塞,因此无法退出。 Using a get method with a timeout instead did the trick. 使用带有超时的get方法可以解决问题。 I have the code for just the run method that I modified below 我只有下面修改的run方法的代码

    def run(self):
            try:
                   #Start Thread
                   printing "Starting %s..."%(self.name)
                   #Do Some processing
                   while not exit_flag:
                          try:
                                data = self.q.get(True,self.timeout)
                                print "%s processing %s"%(self.name,str(data))
                                self.q.task_done()
                          except:
                                 print "Queue Empty or Timeout Occurred. Try Again for %s"%(self.name)


                    # Exit thread
                    print "Exiting %s..."%(self.name)
             except Exception as e:
                print "Exiting %s due to Error: %s"%(self.name,str(e))

If you want to force all the threads to exit when the process exits, you can set the "daemon" flag of the thread to True before the thread is created. 如果要在进程退出时强制所有线程退出,则可以在创建线程之前将线程的“守护程序”标志设置为True。

http://docs.python.org/2/library/threading.html#threading.Thread.daemon http://docs.python.org/2/library/threading.html#threading.Thread.daemon

I did it once in C. Basically i had a main process that were starting the other ones and kept tracks of them, ie. 我用C做过一次。基本上,我有一个主要过程来启动其他进程并跟踪它们,即。 stored the PID and waited for the return code. 存储PID并等待返回代码。 If you have an error in a process the code will indicate so and then you can stop every other process. 如果您在进程中有错误,代码将指示错误,然后您可以停止所有其他进程。 Hope this helps 希望这可以帮助

Edit: 编辑:

Sorry i can have forgotten in my answer that you were using threads. 抱歉,我可能忘记了您使用的线程。 But I think it still applies. 但我认为它仍然适用。 You can either wrap or modify the thread to get a return value or you can use the multithread pool library. 您可以包装或修改线程以获取返回值,也可以使用多线程池库。

how to get the return value from a thread in python? 如何从python中的线程获取返回值?

Python thread exit code Python线程退出代码

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM