“杀死”线程

在Python中后台线程无法被杀死,那么如何终止线程呢?

import random
import threading
import time

def bg_thread():
    for i in range(1, 30):
        print(f'{i} of 30 iterations...')
        # do some work...
        time.sleep(random.random())  

    print(f'{i} iterations completed before exiting.')

th = threading.Thread(target=bg_thread)
th.start()
th.join()    

运行该程序,并使其打印几行。按Ctrl + C  中断它。

  你会发现我按了两次 Ctrl + C,才使得程序退出。 第一按了Ctrl + C。此时,程序的主线程引发了KeyboardInterrupt异常并想退出,但后台线程未遵从并继续运行。该进程在其主线程中接收到中断信号,并准备退出,但首先需要等待后台线程结束。但是该线程对中断一无所知,所有线程都知道它需要在结束之前完成30次迭代。
  而Python在退出期间使用的等待机制规定了在接收到第二个中断信号时中止。这就是为什么第二个Ctrl-C立即结束该过程的原因。

 

 

守护线程

  所有线程对象都有一个daemon属性。您可以True在启动线程之前将此属性设置为,然后将该线程视为守护程序线程。

  运行该程序,这次,第一个Ctrl + C就导致该过程立即退出。您可能会认为这实际上是杀死线程的一种方法,但是考虑到以这种方式杀死线程,您也必须杀死进程。

import random
import threading
import time

def bg_thread():
    for i in range(1, 30):
        print(f'{i} of 30 iterations...')
        time.sleep(random.random())  

    print(f'{i} iterations completed before exiting.')

th = threading.Thread(target=bg_thread)
th.daemon = True
th.start()
th.join()

  

Python事件

使用守护程序线程是避免必须处理多线程程序中意外中断的一种简便方法,仅在退出进程的特定情况下有效。然而有时应用程序可能想要终止线程而不必杀死自己。

hreading.Event可以使一个线程等待其他线程的通知。其内置了一个标志,初始值为False。线程通过wait()方法进入等待状态,直到另一个线程调用set()方法将内置标志设置为True时,Event通知所有等待状态的线程恢复运行;调用clear()时重置为 False。还可以通过isSet()方法查询Envent对象内置状态的当前值。

Event其实就是一个简化版的 Condition。Event没有锁,无法使线程进入同步阻塞状态。

  • isSet(): 当内置标志为True时返回True。
  • set(): 将标志设为True,并通知所有处于等待阻塞状态的线程恢复运行状态。
  • clear(): 将标志设为False。
  • wait([timeout]): 如果标志为True将立即返回,否则阻塞线程至等待阻塞状态,等待其他线程调用set()。
import random
import signal
import threading
import time

exit_event = threading.Event()


def bg_thread():
    for i in range(1, 30):
        print(f'{i} of 30 iterations...')
        time.sleep(random.random())  # do some work...

        if exit_event.is_set():
            break

    print(f'{i} iterations completed before exiting.')


def signal_handler(signum, frame):
    exit_event.set()


signal.signal(signal.SIGINT, signal_handler)
th = threading.Thread(target=bg_thread)
th.start()
th.join()

 

for i in range(1, 30):
    print(f'{i} of 30 iterations...')
    if exit_event.wait(timeout=random.random()):
        break

 

 

https://blog.miguelgrinberg.com/post/how-to-kill-a-python-thread

https://blog.csdn.net/brucewong0516/article/details/84588804

posted @ 2021-05-21 15:57  薄荷味日记  阅读(461)  评论(0编辑  收藏  举报