Как остановить потоки в python3 [duplicate]

Альтернативный вариант из пакета easypackages. После установки вы можете загружать пакеты наиболее интуитивно понятным способом:

libraries("plyr", "psych", "tm")

В пакет также входит функция установки нескольких пакетов:

packages("plyr", "psych", "tm")

Ссылка здесь .

590
задан igaurav 22 September 2014 в 14:04
поделиться

23 ответа

Как правило, это плохой шаблон, чтобы убить поток внезапно, на 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, он не поймает прерывание.

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

538
ответ дан Richard Möhn 26 August 2018 в 00:33
поделиться

Это плохой ответ, см. комментарии

Вот как это сделать:

from threading import *

...

for thread in enumerate():
    if thread.isAlive():
        try:
            thread._Thread__stop()
        except:
            print(str(thread.getName()) + ' could not be terminated'))

Дайте ему несколько секунд, затем ваш поток следует остановить. Проверьте также метод thread._Thread__delete().

Я бы рекомендовал метод thread.quit() для удобства. Например, если у вас есть сокет в вашем потоке, я бы рекомендовал создать метод quit() в вашем классе сокета-дескриптора, завершить сокет, а затем запустить thread._Thread__stop() внутри вашего quit().

1
ответ дан Aaron Hall 26 August 2018 в 00:33
поделиться

Следующее обходное решение может быть использовано для уничтожения потока:

kill_threads = False

def doSomething():
    global kill_threads
    while True:
        if kill_threads:
            thread.exit()
        ......
        ......

thread.start_new_thread(doSomething, ())

Это можно использовать даже для завершения потоков, код которых написан в другом модуле, из основного потока. Мы можем объявить глобальную переменную в этом модуле и использовать ее для прекращения потоков / s, порожденных в этом модуле.

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

0
ответ дан Amit Chahar 26 August 2018 в 00:33
поделиться

A multiprocessing.Process может p.terminate()

В тех случаях, когда я хочу убить поток, но не хочу использовать флаги / блокировки / сигналы / семафоры / события / что-то еще, я рекламирую потоки для полномасштабных процессов. Для кода, который использует только несколько потоков, служебные данные не так уж плохи.

Например. это очень удобно, чтобы легко прекратить вспомогательные «потоки», которые выполняют блокировку ввода-вывода

. Преобразование тривиально: в связанном коде замените все threading.Thread на multiprocessing.Process и все queue.Queue на multiprocessing.Queue и добавьте требуемые вызовы p.terminate() к вашему родительскому процессу, который хочет убить его ребенка p

Python doc

63
ответ дан cfi 26 August 2018 в 00:33
поделиться

Одна вещь, которую я хочу добавить, состоит в том, что если вы читаете официальную документацию в threading lib Python , рекомендуется избегать использования «демонических» потоков, когда вы не хотите, чтобы потоки заканчивались внезапно, флаг, который Паоло Ровелли упомянул .

Из официальной документации:

Потоки Daemon внезапно останавливаются при завершении работы. Их ресурсы (такие как открытые файлы, транзакции базы данных и т. Д.) Могут быть недоступны. Если вы хотите, чтобы ваши потоки прекратились изящно, сделайте их недемоническими и используйте подходящий механизм сигнализации, например Event.

Я думаю, что создание демонических потоков зависит от вашего приложения, но в целом (и, на мой взгляд), лучше избегать их убийства или сделать их демоническими. При многопроцессорной обработке вы можете использовать is_alive() для проверки состояния процесса и «завершения» для их завершения (также вы избегаете проблем GIL). Но вы можете найти больше проблем, иногда, когда вы выполняете свой код в Windows.

И всегда помните, что если у вас есть «живые потоки», интерпретатор Python будет работать для их ожидания. (Из-за этой демона может помочь вам, если не имеет значения, резко заканчивается).

4
ответ дан Community 26 August 2018 в 00:33
поделиться

Лучше, если вы не убили нить. Способ может состоять в том, чтобы ввести блок «try» в цикл потока и выбросить исключение, когда вы хотите остановить поток (например, break / return / ..., который останавливает ваш / while / ...). Я использовал это в своем приложении, и он работает ...

9
ответ дан Giancarlo 26 August 2018 в 00:33
поделиться

Для этой цели создана библиотека, stopit . Хотя некоторые из тех же предостережений, перечисленных в настоящем документе, по-прежнему применяются, по крайней мере, эта библиотека представляет собой регулярный, повторяемый метод достижения поставленной цели.

0
ответ дан Jason R. Coombs 26 August 2018 в 00:33
поделиться

Вы можете убить поток, установив трассировку в поток, который выйдет из потока. См. Прикрепленную ссылку для одной возможной реализации.

Убить поток в Python

13
ответ дан Jeff 26 August 2018 в 00:33
поделиться

Как отмечали другие, норма должна установить флаг остановки. Для чего-то легкого (без подкласса Thread, нет глобальной переменной), лямбда-обратный вызов является опцией. (Обратите внимание на круглые скобки в if stop().)

import threading
import time

def do_work(id, stop):
    print("I am thread", id)
    while True:
        print("I am thread {} doing something".format(id))
        if stop():
            print("  Exiting loop.")
            break
    print("Thread {}, signing off".format(id))


def main():
    stop_threads = False
    workers = []
    for id in range(0,3):
        tmp = threading.Thread(target=do_work, args=(id, lambda: stop_threads))
        workers.append(tmp)
        tmp.start()
    time.sleep(3)
    print('main: done sleeping; time to stop the threads.')
    stop_threads = True
    for worker in workers:
        worker.join()
    print('Finis.')

if __name__ == '__main__':
    main()

Замена print() функцией pr(), которая всегда сбрасывается (sys.stdout.flush()), может улучшить точность вывода оболочки.

(проверяется только на Windows / Eclipse / Python3.3)

25
ответ дан Jon Coombs 26 August 2018 в 00:33
поделиться
29
ответ дан Lasse Vågsæther Karlsen 26 August 2018 в 00:33
поделиться

Официального API для этого нет, нет.

Вам нужно использовать API платформы, чтобы убить поток, например. pthread_kill или TerminateThread. Вы можете получить доступ к этому API, например. через pythonwin или через ctypes.

Обратите внимание, что это по своей сути небезопасно. Вероятно, это приведет к бесполезному мусору (от локальных переменных стоп-кадров, которые становятся мусором) и может привести к взаимоблокировкам, если убитый поток имеет GIL в момент его убийства.

99
ответ дан Martin v. Löwis 26 August 2018 в 00:33
поделиться

Если вам действительно нужна возможность убить подзадачу, используйте альтернативную реализацию. multiprocessing и gevent обе поддерживают без разбора «поток».

Threading Python не поддерживает отмену. Даже не пытайся. Ваш код, скорее всего, затормозит, испортит или пропустит память или будет иметь другие непреднамеренные «интересные» трудно отлаживающие эффекты, которые бывают редко и недетерминированно.

-2
ответ дан Matthias Urlichs 26 August 2018 в 00:33
поделиться
7
ответ дан Noctis Skytower 26 August 2018 в 00:33
поделиться

Pieter Hintjens - один из основателей ØMQ -проекта - говорит, используя ØMQ и избегая примитивов синхронизации, таких как блокировки, мьютексы, события и т. д., является самым безопасным и безопасным способом записи многопоточные программы:

http://zguide.zeromq.org/py:all#Multithreading-with-ZeroMQ

Это включает в себя рассказ о ребенке нить, что он должен отменить свою работу. Это будет сделано путем оснащения нити с помощью сокета ØMQ и опроса на этом сокете для сообщения о том, что оно должно быть отменено.

Ссылка также дает пример для многопоточного кода на Python с помощью ØMQ.

0
ответ дан paulkernstock 26 August 2018 в 00:33
поделиться
-1
ответ дан SCB 26 August 2018 в 00:33
поделиться

Если вы пытаетесь завершить всю программу, вы можете установить поток как «демон». см. Thread.daemon

56
ответ дан schettino72 26 August 2018 в 00:33
поделиться

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

import threading
import time
import atexit

def do_work():

  i = 0
  @atexit.register
  def goodbye():
    print ("'CLEANLY' kill sub-thread with value: %s [THREAD: %s]" %
           (i, threading.currentThread().ident))

  while True:
    print i
    i += 1
    time.sleep(1)

t = threading.Thread(target=do_work)
t.daemon = True
t.start()

def after_timeout():
  print "KILL MAIN THREAD: %s" % threading.currentThread().ident
  raise SystemExit

threading.Timer(2, after_timeout).start()

Выход:

0
1
KILL MAIN THREAD: 140013208254208
'CLEANLY' kill sub-thread with value: 2 [THREAD: 140013674317568]
1
ответ дан slumtrimpet 26 August 2018 в 00:33
поделиться

Запустите вспомогательный поток с помощью setDaemon (True).

def bootstrap(_filename):
    mb = ModelBootstrap(filename=_filename) # Has many Daemon threads. All get stopped automatically when main thread is stopped.

t = threading.Thread(target=bootstrap,args=('models.conf',))
t.setDaemon(False)

while True:
    t.start()
    time.sleep(10) # I am just allowing the sub-thread to run for 10 sec. You can listen on an event to stop execution.
    print('Thread stopped')
    break
0
ответ дан Sud 26 August 2018 в 00:33
поделиться

Это основано на thread2 - killable threads (рецепт Python)

Вам нужно вызвать PyThreadState_SetasyncExc (), который доступен только через ctypes.

Это было проверено только на Python 2.7.3, но, скорее всего, оно будет работать с другими недавними версиями 2.x.

import ctypes

def terminate_thread(thread):
    """Terminates a python thread from another thread.

    :param thread: a threading.Thread instance
    """
    if not thread.isAlive():
        return

    exc = ctypes.py_object(SystemExit)
    res = ctypes.pythonapi.PyThreadState_SetAsyncExc(
        ctypes.c_long(thread.ident), exc)
    if res == 0:
        raise ValueError("nonexistent 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(thread.ident, None)
        raise SystemError("PyThreadState_SetAsyncExc failed")
26
ответ дан Sujania 26 August 2018 в 00:33
поделиться
-1
ответ дан user1942887 26 August 2018 в 00:33
поделиться
from ctypes import *
pthread = cdll.LoadLibrary("libpthread-2.15.so")
pthread.pthread_cancel(c_ulong(t.ident))

t - ваш объект Thread.

. Читайте источник python (Modules/threadmodule.c и Python/thread_pthread.h), вы можете видеть, что Thread.ident - это тип pthread_t, поэтому вы может делать все, что pthread может делать в использовании python libpthread.

18
ответ дан Vallentin 26 August 2018 в 00:33
поделиться

Хотя он довольно старый, этот может быть удобным решением для некоторых:

Небольшой модуль, расширяющий функциональность модуля потоковой передачи - позволяет одному потоку поднимать исключений в контексте другого потока. Поднимая SystemExit, вы можете, наконец, уничтожить потоки python.

import threading
import ctypes     

def _async_raise(tid, excobj):
    res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(excobj))
    if res == 0:
        raise ValueError("nonexistent 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(tid, 0)
        raise SystemError("PyThreadState_SetAsyncExc failed")

class Thread(threading.Thread):
    def raise_exc(self, excobj):
        assert self.isAlive(), "thread must be started"
        for tid, tobj in threading._active.items():
            if tobj is self:
                _async_raise(tid, excobj)
                return

        # the thread was alive when we entered the loop, but was not found 
        # in the dict, hence it must have been already terminated. should we raise
        # an exception here? silently ignore?

    def terminate(self):
        # must raise the SystemExit type, instead of a SystemExit() instance
        # due to a bug in PyThreadState_SetAsyncExc
        self.raise_exc(SystemExit)

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

Однако, согласно его исходному источнику , есть некоторые проблемы с этим кодом.

  • Исключение будет возникать только при выполнении байт-кода python. Если ваш поток вызывает встроенную / встроенную функцию блокировки, исключение будет возбуждено только тогда, когда выполнение возвращается к коду python. Также существует проблема, если встроенная функция внутренне вызывает PyErr_Clear (), которая эффективно отменит ваше ожидающее исключение. Вы можете попытаться снова поднять его.
  • Только безопасные типы исключений могут быть подняты. Экземпляры исключений, вероятно, вызовут неожиданное поведение и, таким образом, будут ограничены. Например: t1.raise_exc (TypeError), а не t1.raise_exc (TypeError ("blah")). ИМХО, это ошибка, и я сообщил об этом как об одном. Для получения дополнительной информации http://mail.python.org/pipermail/python-dev/2006-August/068158.html
  • Я попросил разоблачить эту функцию в встроенном -in, но поскольку ctypes стал стандартной библиотекой (по версии 2.5), и эта функция вряд ли будет реализована-агностична, ее можно сохранить неэкспонированной.
0
ответ дан wp78de 26 August 2018 в 00:33
поделиться

Это похоже на работу с pywin32 на windows 7

my_thread = threading.Thread()
my_thread.start()
my_thread._Thread__stop()
-1
ответ дан zzart 26 August 2018 в 00:33
поделиться
Другие вопросы по тегам:

Похожие вопросы: