Чи можливо припинити запущену нитку без встановлення / перевірки прапорів / семафорів / тощо?
Чи можливо припинити запущену нитку без встановлення / перевірки прапорів / семафорів / тощо?
Відповіді:
Це, як правило, поганий зразок, щоб різко вбивати нитку, на 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, *args, **kwargs):
super(StoppableThread, self).__init__(*args, **kwargs)
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 )
(За матеріалами " Вбивчі нитки " Томера Філіба. Цитата про повернене значення, PyThreadState_SetAsyncExc
здається, походить зі старої версії Python .)
Як зазначається в документації, це не чарівна куля, оскільки якщо нитка зайнята поза інтерпретатором Python, вона не вловить переривання.
Хороший шаблон використання цього коду полягає в тому, щоб потік вловлював конкретний виняток і проводив очищення. Таким чином, ви можете перервати завдання і все одно мати належне очищення.
SO_REUSEADDR
опцію socket, щоб уникнути Address already in use
помилок.
None
замість 0
цього res != 1
випадку, і мені довелося зателефонувати ctypes.c_long(tid)
та передати його будь-якій функції ctypes, а не безпосередньо tid.
Немає офіційного API для цього, ні.
Вам потрібно використовувати API платформи, щоб знищити нитку, наприклад, pthread_kill або TerminateThread. Ви можете отримати доступ до такого API, наприклад, через pythonwin або через ctypes.
Зауважте, що це по суті небезпечно. Це, ймовірно, призведе до неприбраного сміття (з локальних змінних кадрів стека, які стають сміттям), і може призвести до тупикових ситуацій, якщо вбита нитка має GIL в точці, коли вона буде вбита.
А multiprocessing.Process
можеp.terminate()
У тих випадках, коли я хочу вбити нитку, але не хочу використовувати прапори / блокування / сигнали / семафори / події / будь-що інше, я просуваю нитки до повномасштабних процесів. Для коду, який використовує лише кілька потоків, накладні витрати не такі вже й погані.
Наприклад, це зручно для легкого припинення допоміжних "потоків", які виконують блокування вводу / виводу
Перетворення тривіальне: у відповідному коді замініть всі threading.Thread
на multiprocessing.Process
і всі queue.Queue
з multiprocessing.Queue
і додайте необхідні виклики p.terminate()
до свого батьківського процесу, який хоче вбити свою дитинуp
Дивіться документаціюmultiprocessing
на Python для .
multiprocessing
приємно, але майте на увазі, що аргументи підбираються до нового процесу. Отже, якщо один із аргументів є неприйнятним (наприклад, а logging.log
), це може бути недоброю ідеєю multiprocessing
.
multiprocessing
аргументи підбираються до нового процесу в Windows, але Linux використовує forking для їх копіювання (Python 3.7, не знаючи, які інші версії). Таким чином, ви отримаєте код, який працює в Linux, але викликає помилки підберезника в Windows.
multiprocessing
з лісозаготівлею - справа хитра. Потрібно скористатися QueueHandler
(див. Цей підручник ). Я навчився цього важким шляхом.
Якщо ви намагаєтеся закінчити всю програму, ви можете встановити потік як "демон". див. Thread.daemon
Як вже згадували інші, норма - встановити прапор зупинки. Для чогось легкого (без підкласу 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)
pr()
функція?
Це засновано на нитках2, які можна захистити (рецепт 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")
KeyboardInterrupt
щоб вони мали можливість очистити. Якщо вони все ще звисають після цього, то SystemExit
це доречно або просто вбити процес з терміналу.
pthread_cleanup_push()/_pop()
цього було б багато роботи, щоб правильно реалізувати, і це помітно сповільнить інтерпретатора.
Ніколи не слід насильно вбивати нитку, не співпрацюючи з нею.
Убиваючи потік, знімаються гарантії, що спроба / остаточно блокується налаштована, щоб ви могли залишити замок заблокованим, файли відкритими тощо.
Єдиний раз, коли ви можете стверджувати, що примусово вбивати теми - це гарна ідея - це вбити програму швидко, але ніколи не поодиноко.
У Python ви просто не можете вбити нитку безпосередньо.
Якщо вам НЕ дійсно потрібно мати нитку (!), То замість того, щоб використовувати пакет для нарізки , ви можете зробити, щоб використовувати багатопроцесорний пакет . Тут, щоб вбити процес, ви можете просто викликати метод:
yourProcess.terminate() # kill the process!
Python знищить ваш процес (у Unix через сигнал SIGTERM, тоді як у Windows через TerminateProcess()
дзвінок). Зверніть увагу, щоб використовувати його під час користування чергою чи трубою! (це може пошкодити дані в черзі / трубі)
Зауважимо, що multiprocessing.Event
і multiprocessing.Semaphore
робота точно так само, як threading.Event
і threading.Semaphore
відповідно. Насправді перші - це клони латерів.
Якщо вам дійсно потрібно використовувати нитку, немає способу вбити її безпосередньо. Однак ви можете скористатися "демоновою ниткою" . Насправді, у Python, Нитка може бути позначена як демон :
yourThread.daemon = True # set the Thread as a "daemon thread"
Основна програма вийде, коли не залишиться жодної живої недемонової нитки. Іншими словами, коли ваша основна нитка (це, звичайно, недемонова нитка) завершить свої операції, програма вийде, навіть якщо ще працюють деякі демонові нитки.
Зауважте, що необхідно встановити Thread так, як daemon
раніше start()
називався метод!
Звичайно, можна і потрібно використовувати daemon
навіть з multiprocessing
. Тут, коли основний процес закінчується, він намагається припинити всі свої демонічні дочірні процеси.
Нарешті, будь ласка, зверніть увагу , що sys.exit()
і os.kill()
не вибір.
Ви можете вбити потік, встановивши слід у нитку, яка вийде з потоку. Дивіться додане посилання для однієї можливої реалізації.
Якщо ви явно телефонуєте time.sleep()
як частину своєї потоку (скажімо, опитуєте якусь зовнішню службу), поліпшенням методу Філліпа є використання тайм-ауту в методі event
s, wait()
де виsleep()
Наприклад:
import threading
class KillableThread(threading.Thread):
def __init__(self, sleep_interval=1):
super().__init__()
self._kill = threading.Event()
self._interval = sleep_interval
def run(self):
while True:
print("Do Something")
# If no kill signal is set, sleep for the interval,
# If kill signal comes in while sleeping, immediately
# wake up and handle
is_killed = self._kill.wait(self._interval)
if is_killed:
break
print("Killing Thread")
def kill(self):
self._kill.set()
Потім запустити його
t = KillableThread(sleep_interval=5)
t.start()
# Every 5 seconds it prints:
#: Do Something
t.kill()
#: Killing Thread
Перевага використання wait()
замість sleep()
ing та регулярної перевірки події полягає в тому, що ви можете програмувати в більш тривалих інтервалах сну, нитка зупиняється майже негайно (коли ви б інакше sleep()
працювали), і на мою думку, код для обробки виходу значно простіший .
Однозначно можливо реалізувати Thread.stop
метод, як показано в наступному прикладі коду:
import sys
import threading
import time
class StopThread(StopIteration):
pass
threading.SystemExit = SystemExit, StopThread
class Thread2(threading.Thread):
def stop(self):
self.__stop = True
def _bootstrap(self):
if threading._trace_hook is not None:
raise ValueError('Cannot run thread with tracing!')
self.__stop = False
sys.settrace(self.__trace)
super()._bootstrap()
def __trace(self, frame, event, arg):
if self.__stop:
raise StopThread()
return self.__trace
class Thread3(threading.Thread):
def _bootstrap(self, stop_thread=False):
def stop():
nonlocal stop_thread
stop_thread = True
self.stop = stop
def tracer(*_):
if stop_thread:
raise StopThread()
return tracer
sys.settrace(tracer)
super()._bootstrap()
###############################################################################
def main():
test1 = Thread2(target=printer)
test1.start()
time.sleep(1)
test1.stop()
test1.join()
test2 = Thread2(target=speed_test)
test2.start()
time.sleep(1)
test2.stop()
test2.join()
test3 = Thread3(target=speed_test)
test3.start()
time.sleep(1)
test3.stop()
test3.join()
def printer():
while True:
print(time.time() % 1)
time.sleep(0.1)
def speed_test(count=0):
try:
while True:
count += 1
except StopThread:
print('Count =', count)
if __name__ == '__main__':
main()
Схоже, Thread3
клас запускає код приблизно на 33% швидше, ніж Thread2
клас.
self.__stop
на наявність потоку. Зауважте, що, як і більшість інших рішень тут, він фактично не перериває блокуючий виклик, оскільки функція відстеження викликається лише при введенні нової локальної області. Також варто відзначити, що sys.settrace
дійсно призначений для реалізації налагоджувачів, профілів тощо, і як такий вважається деталі реалізації CPython, і не гарантується його існування в інших реалізаціях Python.
Thread2
класу є те, що він запускає код приблизно в десять разів повільніше. Деякі люди все ще можуть вважати це прийнятним.
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
.
Для усунення потоку може бути використаний наступний спосіб вирішення:
kill_threads = False
def doSomething():
global kill_threads
while True:
if kill_threads:
thread.exit()
......
......
thread.start_new_thread(doSomething, ())
Це можна використовувати навіть для завершення потоків, код яких записаний в іншому модулі, з основного потоку. Ми можемо оголосити глобальну змінну в цьому модулі і використовувати її для завершення потоку / с, породженого в цьому модулі.
Зазвичай я використовую це для завершення всіх потоків на виході програми. Це може бути не ідеальним способом завершення потоку / потоків, але може допомогти.
Я запізнююсь із цією грою, але я вела боротьбу з подібним питанням, і наступне, здається, обидва вирішує проблему ідеально для мене І дозволяє мені виконати деякі основні перевірки стану та потоку, коли очищений підрядний потік виходить:
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]
SystemExit
на after_timeout
нитку може робити що-небудь з основною ниткою (яка просто чекає колишнього виходу в цьому прикладі)?
SystemExit
має лише два особливих властивості: він не створює прослідкування (коли будь-який потік виходить за допомогою викидання одного), а якщо основний потік виходить, перекинувши його, він встановлює статус виходу (при цьому чекаючи інших недемонних потоків для виходу).
Я хочу додати одне, що якщо ви читаєте офіційну документацію в потоці lib Python , рекомендується уникати використання "демонічних" ниток, коли ви не хочете, щоб теми різко закінчувалися, прапором, який згадував Паоло Ровеллі .
З офіційної документації:
Нитки Демона різко зупиняються при відключенні. Їх ресурси (наприклад, відкриті файли, транзакції бази даних тощо) можуть не бути належним чином випущені. Якщо ви хочете, щоб ваші потоки граціозно зупинялися, зробіть їх недемонічними та використовуйте відповідний механізм сигналізації, такий як подія.
Я думаю, що створення демонічних ниток залежить від вашої програми, але в цілому (і на мою думку) краще уникати їх вбивання або створення їх демонічними. У мультиобробці ви можете використовуватиis_alive()
перевірити стан процесу та "припинити" їх закінчення (Також ви уникнете проблем з GIL). Але іноді ви можете знайти більше проблем під час виконання коду в Windows.
І завжди пам’ятайте, що якщо у вас є "живі нитки", інтерпретатор Python буде працювати на їх очікування. (Через це демон може допомогти вам, якщо все-таки різко не закінчиться).
Для цього побудована бібліотека, стопіт . Хоча деякі із тих самих застережень, які перераховані в цьому документі, все ще застосовуються, принаймні ця бібліотека представляє звичайну, повторювану методику досягнення поставленої мети.
Хоча це досить старе, для деяких це може бути зручним рішенням:
Маленький модуль, який розширює функціональність модуля нитки - дозволяє одному потоку збирати винятки в контексті іншого потоку. Піднімаючи
SystemExit
, ви можете остаточно вбити нитки пітона.
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 ("бла")).
- ІМХО це помилка, і я повідомив про це як про одне. Для отримання додаткової інформації http://mail.python.org/pipermail/python-dev/2006-August/068158.html
- Я попросив розкрити цю функцію у вбудованому модулі потоку, але оскільки ctypes став стандартною бібліотекою (станом на 2.5), і ця
функція, швидше за все, не буде аггностичною, вона може залишатися
невизначеною.
Пітер Хінтьенс - один із засновників ØMQ - говорить, що використання ØMQ та уникнення примітивів синхронізації, таких як замки, мютекси, події тощо, є найбезпечнішим і найбезпечнішим способом написання багатопотокових програм:
http://zguide.zeromq.org/py:all#Multithreading-with-ZeroMQ
Сюди входить сказати дочірній нитці, що вона повинна скасувати свою роботу. Це можна зробити, оснастивши потік ØMQ-сокетом і опитуючи на цьому сокеті повідомлення про те, що він повинен скасувати.
Посилання також надає приклад багатопотокового коду python з ØMQ.
Припускаючи, що ви хочете мати кілька потоків однієї і тієї ж функції, це IMHO найпростіша реалізація, щоб зупинити її на id:
import time
from threading import Thread
def doit(id=0):
doit.stop=0
print("start id:%d"%id)
while 1:
time.sleep(1)
print(".")
if doit.stop==id:
doit.stop=0
break
print("end thread %d"%id)
t5=Thread(target=doit, args=(5,))
t6=Thread(target=doit, args=(6,))
t5.start() ; t6.start()
time.sleep(2)
doit.stop =5 #kill t5
time.sleep(2)
doit.stop =6 #kill t6
Приємно, що тут ви можете мати декілька одних і тих же і різних функцій, і зупинити їх на всіх functionname.stop
Якщо ви хочете мати лише один потік функції, тоді вам не потрібно пам’ятати ідентифікатор. Просто зупиніться, якщо doit.stop
> 0.
Просто для створення ідеї @ SCB (що саме було мені потрібно), щоб створити підклас KillableThread з налаштованою функцією:
from threading import Thread, Event
class KillableThread(Thread):
def __init__(self, sleep_interval=1, target=None, name=None, args=(), kwargs={}):
super().__init__(None, target, name, args, kwargs)
self._kill = Event()
self._interval = sleep_interval
print(self._target)
def run(self):
while True:
# Call custom function with arguments
self._target(*self._args)
# If no kill signal is set, sleep for the interval,
# If kill signal comes in while sleeping, immediately
# wake up and handle
is_killed = self._kill.wait(self._interval)
if is_killed:
break
print("Killing Thread")
def kill(self):
self._kill.set()
if __name__ == '__main__':
def print_msg(msg):
print(msg)
t = KillableThread(10, print_msg, args=("hello world"))
t.start()
time.sleep(6)
print("About to kill thread")
t.kill()
Звичайно, як і у @SBC, потік не чекає запуску нового циклу, щоб зупинитися. У цьому прикладі ви побачите повідомлення "Вбивча нитка", надруковане відразу після "Про те, щоб вбити нитку", замість того, щоб чекати ще 4 секунди, щоб нитка завершилася (оскільки ми проспали вже 6 секунд).
Другий аргумент у конструкторі KillableThread - це ваша спеціальна функція (print_msg тут). Аргумент Args - це аргументи, які будуть використовуватися при виклику функції (("привіт світ")) тут.
Як уже згадувалося в @ Kozyarchuk в відповідь , установка трасування працює. Оскільки ця відповідь не містила коду, ось робочий приклад, готовий до використання:
import sys, threading, time
class TraceThread(threading.Thread):
def __init__(self, *args, **keywords):
threading.Thread.__init__(self, *args, **keywords)
self.killed = False
def start(self):
self._run = self.run
self.run = self.settrace_and_run
threading.Thread.start(self)
def settrace_and_run(self):
sys.settrace(self.globaltrace)
self._run()
def globaltrace(self, frame, event, arg):
return self.localtrace if event == 'call' else None
def localtrace(self, frame, event, arg):
if self.killed and event == 'line':
raise SystemExit()
return self.localtrace
def f():
while True:
print('1')
time.sleep(2)
print('2')
time.sleep(2)
print('3')
time.sleep(2)
t = TraceThread(target=f)
t.start()
time.sleep(2.5)
t.killed = True
Він припиняється після друку 1
та 2
. 3
не друкується.
Ви можете виконати свою команду в процесі, а потім вбити її за допомогою ідентифікатора процесу. Мені потрібно було синхронізувати між двома потоками, одна з яких не повертається сама собою.
processIds = []
def executeRecord(command):
print(command)
process = subprocess.Popen(command, stdout=subprocess.PIPE)
processIds.append(process.pid)
print(processIds[0])
#Command that doesn't return by itself
process.stdout.read().decode("utf-8")
return;
def recordThread(command, timeOut):
thread = Thread(target=executeRecord, args=(command,))
thread.start()
thread.join(timeOut)
os.kill(processIds.pop(), signal.SIGINT)
return;
Запустіть підрядний потік з 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
Це погана відповідь, дивіться коментарі
Ось як це зробити:
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()
.
_Thread__stop()
просто позначає нитку як зупинену , вона фактично не зупиняє нитку! Ніколи цього не робіть. Прочитайте .
Якщо вам справді потрібна можливість вбити підзадачу, використовуйте альтернативну реалізацію. multiprocessing
і gevent
обидва підтримують без розбору вбиття "нитки".
Нарізка Python не підтримує скасування. Навіть не намагайся. Ваш код, ймовірно, може зайти в тупик, пошкодити або просочити пам'ять або мати інші непередбачувані "цікаві" важкі для налагодження ефекти, які трапляються рідко і недетерміновано.