Is er een manier om een thread te doden?

Is het mogelijk om een lopende thread te beëindigen zonder vlaggen/semaforen/etc. in te stellen/te controleren?


Antwoord 1, autoriteit 100%

Het is over het algemeen een slecht patroon om een thread abrupt te beëindigen, in Python en in welke taal dan ook. Denk aan de volgende gevallen:

  • de thread bevat een kritieke bron die correct moet worden gesloten
  • de thread heeft verschillende andere threads gemaakt die ook moeten worden afgebroken.

De leuke manier om dit aan te pakken, als je het je kunt veroorloven (als je je eigen threads beheert), is om een exit_request-vlag te hebben die elke thread regelmatig controleert om te zien of het tijd is om te sluiten.

Bijvoorbeeld:

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()

In deze code moet je stop()aanroepen op de thread wanneer je deze wilt afsluiten, en wachten tot de thread correct wordt afgesloten met join(). De thread moet de stopvlag met regelmatige tussenpozen controleren.

Er zijn echter gevallen waarin je een thread echt moet doden. Een voorbeeld is wanneer u een externe bibliotheek aan het inpakken bent die bezet is voor lange gesprekken, en u wilt deze onderbreken.

Met de volgende code kan (met enkele beperkingen) een uitzondering worden gemaakt in een Python-thread:

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 an 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 exception in the context of the
        thread represented by this instance.
        """
        _async_raise( self._get_my_tid(), exctype )

(Gebaseerd op vermoordendraad door tomer filiba. De quote over de retourwaarde van PyThreadState_SetAsyncExclijkt te zijn van een oud versie van Python .)

Zoals opgemerkt in de documentatie, is dit geen magische kogel omdat als de draad bezig is buiten de Python-tolk, het de onderbreking niet vangt.

Een goed gebruikspatroon van deze code is om de draad een specifieke uitzondering op te vangen en de opruiming uit te voeren. Op die manier kunt u een taak onderbreken en nog steeds een goede opruiming hebben.


2, Autoriteit 17%

Er is geen officiële API om dat te doen, nee.

U moet platform-API gebruiken om de draad te doden, b.v. Pthread_Kill of Terminatethread. Je hebt toegang tot een dergelijke API, b.v. via Pythonwin, of via Cypertes.

Merk op dat dit inherent onveilig is. Het zal waarschijnlijk leiden tot oncollezen vuilnis (van lokale variabelen van de stapelkaders die afval worden), en kunnen leiden tot deadlocks, als de draad wordt gedood, heeft de GIL op het punt waarop het wordt gedood.


3, Autoriteit 17%

a multiprocessing.Processcan p.terminate()

In de gevallen waarin ik een draad wil doden, maar geen vlaggen / sloten / signalen / semaforen / evenementen / wat dan ook willen gebruiken, promoot ik de threads aan volledige geblazen processen. Voor code die gebruik maakt van slechts een paar threads is de overhead niet zo slecht.

b.g. Dit komt handig om helper “threads” gemakkelijk te beëindigen, die het blokkeren I / O

uitvoeren

De conversie is triviaal: in gerelateerde code Vervang alle threading.Threadmet multiprocessing.Processen alle queue.Queuemet multiprocessing.Queueen voeg de vereiste oproepen toe van p.terminate()aan uw ouderproces dat zijn kind wil doden p

Zie de python documentatie voor multiprocessing.

Voorbeeld:

import multiprocessing
proc = multiprocessing.Process(target=your_proc_function, args=())
proc.start()
# Terminate the process
proc.terminate()  # sends a SIGTERM

4, Autoriteit 12%

Als u probeert het hele programma te beëindigen, kunt u de draad instellen als een “daemon”. zien
Thread.daemon


Antwoord 5, autoriteit 8%

Zoals anderen al hebben gezegd, is het de norm om een stopvlag in te stellen. Voor iets lichtgewichts (geen subclassificatie van Thread, geen globale variabele), is een lambda-callback een optie. (Let op de haakjes in 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()

Het vervangen van print()door een pr()-functie die altijd flusht (sys.stdout.flush()) kan de precisie verbeteren van de shell-uitgang.

(Alleen getest op Windows/Eclipse/Python3.3)


Antwoord 6, autoriteit 5%

Dit is gebaseerd op thread2 — killable threads (Python-recept)

Je moet PyThreadState_SetasyncExc() aanroepen, wat alleen beschikbaar is via ctypes.

Dit is alleen getest op Python 2.7.3, maar het werkt waarschijnlijk ook met andere recente 2.x-releases.

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")

7, Autoriteit 4%

Je moet nooit met geweld een draad doden zonder ermee samen te werken.

Het doden van een thread verwijdert alle garanties die proberen / eindelijk blokken instellen, zodat u vergrendelingen vergrendeld, bestanden openen, enz.

De enige keer dat u kunt beweren dat gedwongen dodende draden een goed idee is is om een ​​programma snel te doden, maar nooit enkele threads.


8, Autoriteit 2%

U kunt een draad doden door trace in de draad te installeren die de draad zal verlaten. Zie bijgevoegde link voor een mogelijke implementatie.

Dood een draad in Python


9

Het is beter als je geen draad doodt.
Een manier kan zijn om een ​​”poging” -blok in de cyclus van de draad in te voeren en een uitzondering te gooien wanneer u de thread wilt stoppen (bijvoorbeeld een pauze / retour / … die uw voor / terwijl / …) stopt.
Ik heb dit op mijn app gebruikt en het werkt …


10

Het is zeker mogelijk om een Thread.stopmethode te implementeren zoals getoond in de volgende voorbeeldcode:

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()

De klasse Thread3lijkt code ongeveer 33% sneller uit te voeren dan de klasse Thread2.


Antwoord 11

Ik ben veel te laat met deze game, maar ik worstel met een vergelijkbare vraagen het volgende verschijnt om zowel het probleem perfect voor mij op te lossen EN me wat basis threadstatus te laten controleren en op te ruimen wanneer de gedemoniseerde subthread wordt afgesloten:

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()

Opbrengst:

0
1
KILL MAIN THREAD: 140013208254208
'CLEANLY' kill sub-thread with value: 2 [THREAD: 140013674317568]

Antwoord 12

De volgende tijdelijke oplossing kan worden gebruikt om een thread te beëindigen:

kill_threads = False
def doSomething():
    global kill_threads
    while True:
        if kill_threads:
            thread.exit()
        ......
        ......
thread.start_new_thread(doSomething, ())

Dit kan zelfs worden gebruikt voor het beëindigen van threads, waarvan de code in een andere module is geschreven, van de hoofdthread. We kunnen een globale variabele in die module declareren en deze gebruiken om thread(s) die in die module zijn voortgebracht, te beëindigen.

Ik gebruik dit meestal om alle threads bij het afsluiten van het programma te beëindigen. Dit is misschien niet de perfecte manier om thread(s) te beëindigen, maar zou kunnen helpen.


Antwoord 13

from ctypes import *
pthread = cdll.LoadLibrary("libpthread-2.15.so")
pthread.pthread_cancel(c_ulong(t.ident))

tis uw Thread-object.

Lees de python-bron (Modules/threadmodule.cen Python/thread_pthread.h) je kunt zien dat de Thread.identeen pthread_ttype, dus je kunt alles doen wat pthreadkan doen in python, gebruik libpthread.


Antwoord 14

Eén ding dat ik wil toevoegen is dat als je de officiële documentatie leest in threading lib Python , het wordt aanbevolen om het gebruik van “demonische” threads te vermijden, als u niet wilt dat threads abrupt eindigen, met de vlag die Paolo Rovelli vermeld.

Uit officiële documentatie:

Daemon-threads worden abrupt gestopt bij afsluiten. Hun bronnen (zoals open bestanden, databasetransacties, enz.) worden mogelijk niet correct vrijgegeven. Als je wilt dat je threads netjes stoppen, maak ze dan niet-demonisch en gebruik een geschikt signaleringsmechanisme zoals een Event.

Ik denk dat het maken van daemonic-threads afhangt van je toepassing, maar in het algemeen (en naar mijn mening) is het beter om ze niet te doden of daemonic te maken. Bij multiprocessing kunt u is_alive()gebruiken om de processtatus te controleren en te “beëindigen” om ze af te ronden (u vermijdt ook GIL-problemen). Maar u kunt soms meer problemen tegenkomen wanneer u uw code uitvoert in Windows.

en onthoud altijd dat als u “live threads” hebt, de Python-tolk zal worden uitgevoerd om ze te wachten. (Vanwege dit daemonic kan u helpen als het niet belangrijk is om het abrupt eindigt).


15

Er is een bibliotheek die voor dit doel is gebouwd, stopit . Hoewel sommige hierin nog steeds van dezelfde waarschuwingen zijn opgesomd, presenteert deze bibliotheek ten minste een reguliere, herhaalbare techniek voor het bereiken van het vermelde doel.


16

Hier is nog een andere manier om het te doen, maar met extreem schone en eenvoudige code, die in Python 3.7 werkt in 2021:

import ctypes 
def kill_thread(thread):
    """
    thread: a threading.Thread object
    """
    thread_id = thread.ident
    res = ctypes.pythonapi.PyThreadState_SetAsyncExc(thread_id, ctypes.py_object(SystemExit))
    if res > 1:
        ctypes.pythonapi.PyThreadState_SetAsyncExc(thread_id, 0)
        print('Exception raise failure')

aangepast vanaf hier: https: // www. geeksforgeeks.org/pyphon-different-wayt-to-kill—-thread/


17

Alleen om op te bouwen op het idee van @ SCB (dat precies was wat ik nodig had) om een ​​killableethread-subklasse te maken met een aangepaste functie:

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()

Natuurlijk, zoals met @sbc, wacht de draad niet om een ​​nieuwe lus te laten stoppen. In dit voorbeeld ziet u het bericht “Killing thread” afgedrukt direct na het “ongeveer om draad” in plaats van nog 4 seconden te wachten voor de draad om te voltooien (aangezien we al 6 seconden 6 seconden hebben geslapen).

Tweede argument in KillablethRead-constructeur is uw aangepaste functie (print_msg hier). Argumenten Argument zijn de argumenten die zullen worden gebruikt bij het bellen van de functie ((“Hallo World”)) hier.


18

Hoewel het nogal oud is, dit is misschien handig oplossing voor sommige:

Een kleine module die de module-functionaliteit van de threading uitbreidt –
staat één draad toe om uitzonderingen in de context van een ander te verhogen
draad. Door het opheffen van SystemExit, kunt u eindelijk Python Threads doden.

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)

Dus, het staat een “thread toe om uitzonderingen te genereren in de context van een andere thread” en op deze manier kan de beëindigde thread de beëindiging afhandelen zonder regelmatig een afbreekvlag te controleren.

Volgens de oorspronkelijke bronzijn er echter enkele problemen met deze code.

p>

  • De uitzondering wordt alleen gegenereerd bij het uitvoeren van python-bytecode. Als je thread een native/ingebouwde blokkeerfunctie aanroept,
    uitzondering wordt alleen gegenereerd wanneer de uitvoering terugkeert naar de python
    code.

    • Er is ook een probleem als de ingebouwde functie intern PyErr_Clear() aanroept, wat in feite je lopende uitzondering zou annuleren.
      Je kunt proberen het opnieuw te verhogen.
  • Alleen uitzonderingstypen kunnen veilig worden verhoogd. Uitzonderingsinstanties veroorzaken waarschijnlijk onverwacht gedrag en zijn dus beperkt.
  • Ik heb gevraagd om deze functie in de ingebouwde threadmodule beschikbaar te stellen, maar aangezien ctypes een standaardbibliotheek is geworden (vanaf 2.5), en dit
    functie is waarschijnlijk niet implementatie-agnostisch, deze kan worden behouden
    onbelicht.

Antwoord 19

Ervan uitgaande dat je meerdere threads van dezelfde functie wilt hebben, is dit IMHO de gemakkelijkste implementatie om één voor id te stoppen:

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

Het leuke is dat je meerdere dezelfde en verschillende functies kunt hebben en ze allemaal kunt stoppen door functionname.stop

Als u slechts één thread van de functie wilt hebben, hoeft u de id niet te onthouden. Stop gewoon, als doit.stop> 0.


Antwoord 20

Zoals vermeld in het antwoord, het installeren van sporenwerken. Aangezien dit antwoord geen code bevatte, is hier een werkend kant-en-klaar voorbeeld:

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

Het stopt na het afdrukken van 1en 2. 3wordt niet afgedrukt.


Antwoord 21

Dit lijkt te werken met pywin32 op Windows 7

my_thread = threading.Thread()
my_thread.start()
my_thread._Thread__stop()

Antwoord 22

Pieter Hintjens — een van de oprichters van het ØMQ-project — zegt: het gebruik van ØMQ en het vermijden van synchronisatieprimitieven zoals sloten, mutexen, gebeurtenissen enz., is de gezondste en veiligste manier om multi-threaded programma’s te schrijven:

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

Dit houdt ook in dat een onderliggende thread wordt verteld dat deze zijn werk moet annuleren. Dit zou worden gedaan door de thread uit te rusten met een ØMQ-socket en op die socket te pollen voor een bericht dat het moet worden geannuleerd.

De link geeft ook een voorbeeld van multi-threaded python-code met ØMQ.


Antwoord 23

Python-versie: 3.8

De daemon-thread gebruiken om uit te voeren wat we wilden, als we de daemon-thread willen beëindigen, hoeven we alleen de parent-thread af te sluiten, waarna het systeem de daemon-thread beëindigt die de parent-thread heeft gemaakt.

Ondersteunt ook de coroutine- en coroutine-functie.

def main():
    start_time = time.perf_counter()
    t1 = ExitThread(time.sleep, (10,), debug=False)
    t1.start()
    time.sleep(0.5)
    t1.exit()
    try:
        print(t1.result_future.result())
    except concurrent.futures.CancelledError:
        pass
    end_time = time.perf_counter()
    print(f"time cost {end_time - start_time:0.2f}")

hieronder staat de ExitThread-broncode

import concurrent.futures
import threading
import typing
import asyncio
class _WorkItem(object):
    """ concurrent\futures\thread.py
    """
    def __init__(self, future, fn, args, kwargs, *, debug=None):
        self._debug = debug
        self.future = future
        self.fn = fn
        self.args = args
        self.kwargs = kwargs
    def run(self):
        if self._debug:
            print("ExitThread._WorkItem run")
        if not self.future.set_running_or_notify_cancel():
            return
        try:
            coroutine = None
            if asyncio.iscoroutinefunction(self.fn):
                coroutine = self.fn(*self.args, **self.kwargs)
            elif asyncio.iscoroutine(self.fn):
                coroutine = self.fn
            if coroutine is None:
                result = self.fn(*self.args, **self.kwargs)
            else:
                result = asyncio.run(coroutine)
            if self._debug:
                print("_WorkItem done")
        except BaseException as exc:
            self.future.set_exception(exc)
            # Break a reference cycle with the exception 'exc'
            self = None
        else:
            self.future.set_result(result)
class ExitThread:
    """ Like a stoppable thread
    Using coroutine for target then exit before running may cause RuntimeWarning.
    """
    def __init__(self, target: typing.Union[typing.Coroutine, typing.Callable] = None
                 , args=(), kwargs={}, *, daemon=None, debug=None):
        #
        self._debug = debug
        self._parent_thread = threading.Thread(target=self._parent_thread_run, name="ExitThread_parent_thread"
                                               , daemon=daemon)
        self._child_daemon_thread = None
        self.result_future = concurrent.futures.Future()
        self._workItem = _WorkItem(self.result_future, target, args, kwargs, debug=debug)
        self._parent_thread_exit_lock = threading.Lock()
        self._parent_thread_exit_lock.acquire()
        self._parent_thread_exit_lock_released = False  # When done it will be True
        self._started = False
        self._exited = False
        self.result_future.add_done_callback(self._release_parent_thread_exit_lock)
    def _parent_thread_run(self):
        self._child_daemon_thread = threading.Thread(target=self._child_daemon_thread_run
                                                     , name="ExitThread_child_daemon_thread"
                                                     , daemon=True)
        self._child_daemon_thread.start()
        # Block manager thread
        self._parent_thread_exit_lock.acquire()
        self._parent_thread_exit_lock.release()
        if self._debug:
            print("ExitThread._parent_thread_run exit")
    def _release_parent_thread_exit_lock(self, _future):
        if self._debug:
            print(f"ExitThread._release_parent_thread_exit_lock {self._parent_thread_exit_lock_released} {_future}")
        if not self._parent_thread_exit_lock_released:
            self._parent_thread_exit_lock_released = True
            self._parent_thread_exit_lock.release()
    def _child_daemon_thread_run(self):
        self._workItem.run()
    def start(self):
        if self._debug:
            print(f"ExitThread.start {self._started}")
        if not self._started:
            self._started = True
            self._parent_thread.start()
    def exit(self):
        if self._debug:
            print(f"ExitThread.exit exited: {self._exited} lock_released: {self._parent_thread_exit_lock_released}")
        if self._parent_thread_exit_lock_released:
            return
        if not self._exited:
            self._exited = True
            if not self.result_future.cancel():
                if self.result_future.running():
                    self.result_future.set_exception(concurrent.futures.CancelledError())

Antwoord 24

Als je echt de mogelijkheid nodig hebt om een subtaak te beëindigen, gebruik dan een alternatieve implementatie. multiprocessingen geventondersteunen beide het willekeurig doden van een “thread”.

Python’s threading ondersteunt geen annulering. Probeer het niet eens. Het is zeer waarschijnlijk dat uw code vastloopt, geheugen corrumpeert of lekt, of andere onbedoelde “interessante” moeilijk te debuggen effecten heeft die zelden en niet-deterministisch optreden.


Antwoord 25

U kunt uw opdracht in een proces uitvoeren en het vervolgens doden met behulp van de proces-id.
Ik moest synchroniseren tussen twee threads waarvan er één niet vanzelf terugkeert.

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;

Antwoord 26

Start de subthread met 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

Antwoord 27

Dit is een slecht antwoord, zie de opmerkingen

Zo doe je het:

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

Geef het een paar seconden, dan zou je thread moeten worden gestopt. Controleer ook de thread._Thread__delete()methode.

Ik zou voor het gemak een thread.quit()methode aanraden. Als je bijvoorbeeld een socket in je thread hebt, raad ik aan om een quit()-methode in je socket-handle-klasse te maken, de socket te beëindigen en vervolgens een thread._Thread__stop()in je quit().

Other episodes