Графана: Ошибка ответа при попытке загрузить как XMLHttpRequest

Как правило, это плохой шаблон, чтобы убить поток внезапно, на Python и на любом языке. Подумайте о следующих случаях:

  • поток содержит критический ресурс, который должен быть закрыт должным образом
  • , поток создал несколько других потоков, которые также должны быть убиты.

Хороший способ справиться с этим, если вы можете себе это позволить (если вы управляете своими потоками), должен иметь флаг exit_request, который каждый поток проверяет на регулярном интервале, чтобы узнать, чтобы выйти.

Например:

import threading

class StoppableThread(threading.Thread):
    """Thread class with a stop() method. The thread itself has to check
    regularly for the stopped() condition."""

    def __init__(self):
        super(StoppableThread, self).__init__()
        self._stop_event = threading.Event()

    def stop(self):
        self._stop_event.set()

    def stopped(self):
        return self._stop_event.is_set()

В этом коде вы должны вызвать stop () в потоке, когда хотите, чтобы он вышел, и дождитесь, пока поток выйдите правильно, используя join (). Поток должен проверять флаг остановки через регулярные промежутки времени.

Однако есть случаи, когда вам действительно нужно убить поток. Например, когда вы завершаете внешнюю библиотеку, занятую для длинных вызовов, и вы хотите ее прервать.

Следующий код позволяет (с некоторыми ограничениями) поднимать исключение в потоке Python:

def _async_raise(tid, exctype):
    '''Raises an exception in the threads with id tid'''
    if not inspect.isclass(exctype):
        raise TypeError("Only types can be raised (not instances)")
    res = ctypes.pythonapi.PyThreadState_SetAsyncExc(ctypes.c_long(tid),
                                                     ctypes.py_object(exctype))
    if res == 0:
        raise ValueError("invalid thread id")
    elif res != 1:
        # "if it returns a number greater than one, you're in trouble,
        # and you should call it again with exc=NULL to revert the effect"
        ctypes.pythonapi.PyThreadState_SetAsyncExc(ctypes.c_long(tid), None)
        raise SystemError("PyThreadState_SetAsyncExc failed")

class ThreadWithExc(threading.Thread):
    '''A thread class that supports raising exception in the thread from
       another thread.
    '''
    def _get_my_tid(self):
        """determines this (self's) thread id

        CAREFUL : this function is executed in the context of the caller
        thread, to get the identity of the thread represented by this
        instance.
        """
        if not self.isAlive():
            raise threading.ThreadError("the thread is not active")

        # do we have it cached?
        if hasattr(self, "_thread_id"):
            return self._thread_id

        # no, look for it in the _active dict
        for tid, tobj in threading._active.items():
            if tobj is self:
                self._thread_id = tid
                return tid

        # TODO: in python 2.6, there's a simpler way to do : self.ident

        raise AssertionError("could not determine the thread's id")

    def raiseExc(self, exctype):
        """Raises the given exception type in the context of this thread.

        If the thread is busy in a system call (time.sleep(),
        socket.accept(), ...), the exception is simply ignored.

        If you are sure that your exception should terminate the thread,
        one way to ensure that it works is:

            t = ThreadWithExc( ... )
            ...
            t.raiseExc( SomeException )
            while t.isAlive():
                time.sleep( 0.1 )
                t.raiseExc( SomeException )

        If the exception is to be caught by the thread, you need a way to
        check that your thread has caught it.

        CAREFUL : this function is executed in the context of the
        caller thread, to raise an excpetion in the context of the
        thread represented by this instance.
        """
        _async_raise( self._get_my_tid(), exctype )

(На основе Killable Threads от Tomer Filiba. Цитата о возвратном значении PyThreadState_SetAsyncExc, по-видимому, принадлежит старой версии Python .)

Как отмечено в документации, это не волшебная пуля, потому что если поток занят вне интерпретатора Python, он не поймает прерывание.

Хорошая схема использования этого кода, чтобы поток зависел от конкретного исключения и выполнял очистку. Таким образом, вы можете прервать задачу и по-прежнему иметь правильную очистку.

0
задан kumaranc 31 December 2018 в 09:47
поделиться