Home >Backend Development >Python Tutorial >How to terminate a thread in python

How to terminate a thread in python

藏色散人
藏色散人Original
2021-03-02 14:02:3460570browse

How to terminate a thread in python: 1. Call the stop function and use the join function to wait for the thread to exit appropriately; 2. Raise an Exception in the python thread; 3. Use "thread.join" to end the thread .

How to terminate a thread in python

The operating environment of this article: Windows 7 system, python version 3.5, DELL G3 computer.

Preface·Zero

We know that to terminate a thread in python, the conventional method is to set/check--->flag or lock of.

Is this method good?

It should not be very good! Because in all programming languages, terminating a thread suddenly is not a good design pattern in any case.

At the same time

In some cases it is even worse, such as:

  • When a thread opens a critical resource that must be closed reasonably, such as opening a Readable and writable files;
  • The thread has created several other threads, and these threads also need to be closed (there is a risk of descendant threads wandering!).

To put it simply, a large group of our threads are co-located with common resources. You want one of the threads to "leave". If this thread happens to occupy resources, then it will be forced to leave. It’s just that the resources are locked up and no one can get them! Isn’t it a bit similar to the plot of a novel about cultivating immortals?

Do you know why threading only has start but no end?

You see, threads are generally used for network connections, releasing system resources, and dumping streaming files. These are all related to IO. If you suddenly close the thread, what should you do if these
are not closed properly? Are you just creating bugs for yourself? ah? !

So the most important thing in this kind of thing is not to terminate the thread but to clean up the thread.

Solution · 一

A nicer way is to have each thread with an exit request flag, and check it at a certain interval in the thread to see if it should Left by myself!

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

As shown in this part of the code, when you want to exit the thread you should explicitly call the stop() function, and use the join() function to wait for the thread to exit appropriately. Threads should periodically check the stop flag.

However, there are some usage scenarios where you really need to kill a thread: for example, when you encapsulate an external library, but the external library calls for a long time, so you Want to interrupt this process.

[Recommended: python video tutorial]

Solution · 2

The next solution is to allow raising an Exception in the python thread (of course There are some restrictions).

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(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(tid, 0)
        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 )

As described in the comments, this is not a "panacea", because if the thread is busy outside the python interpreter, then the terminal exception will not be caught~

This code The reasonable way to use it is to let the thread catch a specific exception and then perform the cleanup operation. This way you can terminate a task and clean it up appropriately.

Solution · 3

If we want to do something similar to the interrupt method, then we can use the thread.join method.

join的原理就是依次检验线程池中的线程是否结束,没有结束就阻塞直到线程结束,如果结束则跳转执行下一个线程的join函数。

先看看这个:

1. 阻塞主进程,专注于执行多线程中的程序。

2. 多线程多join的情况下,依次执行各线程的join方法,前头一个结束了才能执行后面一个。

3. 无参数,则等待到该线程结束,才开始执行下一个线程的join。

4. 参数timeout为线程的阻塞时间,如 timeout=2 就是罩着这个线程2s 以后,就不管他了,继续执行下面的代码。
# coding: utf-8
# 多线程join
import threading, time  
def doWaiting1():  
    print 'start waiting1: ' + time.strftime('%H:%M:%S') + "\n"  
    time.sleep(3)  
    print 'stop waiting1: ' + time.strftime('%H:%M:%S') + "\n" 

def doWaiting2():  
    print 'start waiting2: ' + time.strftime('%H:%M:%S') + "\n"   
    time.sleep(8)  
    print 'stop waiting2: ', time.strftime('%H:%M:%S') + "\n"  

tsk = []    
thread1 = threading.Thread(target = doWaiting1)  
thread1.start()  
tsk.append(thread1)

thread2 = threading.Thread(target = doWaiting2)  
thread2.start()  
tsk.append(thread2)

print 'start join: ' + time.strftime('%H:%M:%S') + "\n"   
for tt in tsk:
    tt.join()
print 'end join: ' + time.strftime('%H:%M:%S') + "\n"

The default join method is no parameters, blocking mode, and other threads will only run after the child thread has finished running.

1. Two threads are started at the same time, and the join function is executed.

2. After the waiting1 thread executes (waits) for 3 seconds, it ends.

3. After the waiting2 thread executes (waits) for 8s, the operation ends.

4. The join function (returned to the main process) ends.

This is the default join method, which is to join after the thread has started running. Pay attention to this. After joining, the main thread must wait for the child thread to finish before returning. main line.

The parameter of join, that is, the timeout parameter, is changed to 2, that is, join (2), then the result is as follows:

  1. two Two threads are started at the same time, and the join function is executed.

  2. wating1 thread completed after executing (waiting) for three seconds.

  3. join exit (two 2s, a total of 4s, 36-32=4, correct).

  4. waiting2 thread did not complete within the waiting time (4s) specified by join, so it completed its execution later.

join(2) is: I will give you two seconds for the sub-thread. After each 2s is over, I will leave. I will not have the slightest chance. concern!

The above is the detailed content of How to terminate a thread in python. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn