简体   繁体   English

如何在多线程python应用程序中创建全局错误处理程序

[英]How to create global error handler in a multi-threaded python applcation

I am developing a multi-threaded application in python. 我正在用python开发多线程应用程序。 I have following scenario. 我有以下情况。

  1. There are 2-3 producer threads which communicate with DB and get some data in large chunks and fill them up in a queue 有2-3个生产者线程与DB通信,并获取大量数据并将其填充到队列中
  2. There is an intermediate worker which breaks large chunks fetched by producer threads into smaller ones and fill them up in another queue. 有一个中间工作程序,它将生产者线程获取的大块分解为较小的块,并将其填充到另一个队列中。
  3. There are 5 consumer threads which consume queue created by intermediate worker thread. 有5个使用者线程消耗由中间工作线程创建的队列。
  4. objects of data sources are accessed by producer threads through their API. 生产者线程通过其API访问数据源的对象。 these data sources are completely separate. 这些数据源是完全独立的。 So these producer understands only presence or absence of data which is supposed to be given out by data source object. 因此,这些生产者仅了解应该由数据源对象发出的数据的存在与否。
  5. I create threads of these three types and i make main thread wait for completion of these threads by calling join() on them. 我创建这三种类型的线程,并通过对它们调用join()使主线程等待这些线程的完成。

Now for such a setup I want a common error handler which senses failure of any thread, any exception and decides what to do. 现在,对于这样的设置,我需要一个通用的错误处理程序,该处理程序可以检测任何线程,任何异常的失败并确定要执行的操作。 For eg if I press ctrl+c after I start my application, main thread dies but producer, consumer threads continue to run. 例如,如果我在启动应用程序后按ctrl + c,则主线程死亡,但生产者,使用者线程继续运行。 I would like that once ctrl+c is pressed entire application should shut down. 我希望一旦按下ctrl + c,就应该关闭整个应用程序。 Similarly if some DB error occurs in data source module, then producer thread should get notified of that. 同样,如果在数据源模块中发生一些DB错误,则生产者线程应该得到通知。

This is what I have done so far: 到目前为止,这是我所做的:

I have created a class ThreadManager, it's object is passed to all threads. 我创建了一个ThreadManager类,它的对象被传递给所有线程。 I have written an error handler method and passed it to sys.excepthook . 我编写了一个错误处理程序方法,并将其传递给sys.excepthook This handler should catch exceptions, error and then it should call methods of ThreadManager class to control the running threads. 该处理程序应捕获异常,错误,然后应调用ThreadManager类的方法来控制正在运行的线程。 Here is snippet: 这是代码段:

class Producer(threading.Thread):
    ....
    def produce():
        data = dataSource.getData()

class DataSource:
    ....
    def getData():
        raise Exception("critical")

def customHandler(exceptionType, value, stackTrace):
     print "In custom handler"

sys.excepthook = customHandler

Now when a thread of producer class calls getData() of DataSource class, exception is thrown. 现在,当生产者类的线程调用DataSource类的getData()时,将引发异常。 But this exception is never caught by my customHandler method. 但是我的customHandler方法从未捕获过此异常。

What am I missing? 我想念什么? Also in such scenario what other strategy can I apply? 同样在这种情况下,我还可以采用什么其他策略? Please help. 请帮忙。 Thank you for having enough patience to read all this :) 感谢您有足够的耐心阅读所有这些内容:)

What you need is a decorator. 您需要的是一个装饰器。 In essence you are modifying your original function and putting in inside a try-except: 本质上,您正在修改原始功能,并放入try-except中:

def exception_decorator(func):
    def _function(*args):
        try:
            result = func(*args)
        except:
            print('*** ESC default handler ***')
            os._exit(1)
        return result
    return _function

If your thread function is called myfunc, then you add the following line above your function definition 如果您的线程函数称为myfunc,则在函数定义上方添加以下行

@exception_decorator
def myfunc():
    pass;

Can't you just catch "KeyboardInterrupt" when pressing Ctrl+C and do: 您不能仅在按Ctrl + C时捕获“ KeyboardInterrupt”并执行以下操作:

for thread in threading.enumerate():
    thread._Thread__stop()
    thread._Thread__delete()
while len(threading.enumerate()) > 1:
    time.sleep(1)
os._exit(0)

and have a flag in each threaded class which is self.alive you could theoretically call thread.alive = False and have it stop gracefully? 并在每个线程类中都有一个self.alive标志,从理论上讲,您可以调用thread.alive = False并使其正常停止吗?

for thread in threading.enumerate():
    thread.alive = False
    time.sleep(5) # Grace period
    thread._Thread__stop()
    thread._Thread__delete()
while len(threading.enumerate()) > 1:
    time.sleep(1)
os._exit(0)

example: 例:

import os
from threading import *
from time import sleep

class worker(Thread):
    def __init__(self):
        self.alive = True
        Thread.__init__(self)
        self.start()
    def run(self):
        while self.alive:
            sleep(0.1)

runner = worker()

try:
    raw_input('Press ctrl+c!')
except:
    pass
for thread in enumerate():
    thread.alive = False
    sleep(1)
    try:
        thread._Thread__stop()
        thread._Thread__delete()
    except:
        pass
# There will always be 1 thread alive and that's the __main__ thread.
while len(enumerate()) > 1:
    sleep(1)
os._exit(0)

Try going about it by changing the internal system exception handler? 尝试通过更改内部系统异常处理程序来解决此问题?

import sys
origExcepthook = sys.excepthook
def uberexcept(exctype, value, traceback):
    if exctype == KeyboardInterrupt:
        print "Gracefully shutting down all the threads"
        # enumerate() thingie here.
    else:
        origExcepthook(exctype, value, traceback)
sys.excepthook = uberexcept

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

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