百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术资源 > 正文

如何杀死一个Python线程

off999 2024-11-21 19:22 31 浏览 0 评论


我经常被问到如何杀死一个后台线程,这个问题的答案让很多人不开心: 线程是杀不死的。在本文中,我将向您展示 Python 中用于终止线程的两个选项。

我经常被问到如何杀死一个后台线程,这个问题的答案让很多人不开心: 线程是杀不死的。在本文中,我将向您展示 Python 中用于终止线程的两个选项。

如果我们是一个好奇宝宝的话,可能会遇到这样一个问题,就是:如何杀死一个 Python 的后台线程呢?我们可能尝试解决这个问题,却发现线程是杀不死的。而本文中将展示,在 Python 中用于终止线程的两个方式。

1. 线程无法结束

A Threaded Example

  • 下面是一个简单的,多线程的示例代码。
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())  # do some work...      print(f'{i} iterations completed before exiting.')  th = threading.Thread(target=bg_thread)  th.start()  th.join() 
  • 使用下面命令来运行程序,在下面的程序运行中,当跑到第 7 次迭代时,按下 Ctrl-C 来中断程序,发现后台运行的程序并没有终止掉。而在第 13 次迭代时,再次按下 Ctrl-C 来中断程序,发现程序真的退出了。
$ python thread.py  1 of 30 iterations...  2 of 30 iterations...  3 of 30 iterations...  4 of 30 iterations...  5 of 30 iterations...  6 of 30 iterations...  7 of 30 iterations...  ^CTraceback (most recent call last):    File "thread.py", line 14, in <module>      th.join()    File "/Users/mgrinberg/.pyenv/versions/3.8.6/lib/python3.8/threading.py", line 1011, in join      self._wait_for_tstate_lock()    File "/Users/mgrinberg/.pyenv/versions/3.8.6/lib/python3.8/threading.py", line 1027, in _wait_for_tstate_lock      elif lock.acquire(block, timeout):  KeyboardInterrupt  8 of 30 iterations...  9 of 30 iterations...  10 of 30 iterations...  11 of 30 iterations...  12 of 30 iterations...  13 of 30 iterations...  ^CException ignored in: <module 'threading' from '/Users/mgrinberg/.pyenv/versions/3.8.6/lib/python3.8/threading.py'>  Traceback (most recent call last):    File "/Users/mgrinberg/.pyenv/versions/3.8.6/lib/python3.8/threading.py", line 1388, in _shutdown      lock.acquire()  KeyboardInterrupt: 
  • 这很奇怪,不是吗?究其原因是,Python 有一些逻辑是会在进程退出前运行的,专门用来等待任何没有被配置为守护线程的后台线程结束,然后再把控制权真正交给操作系统。因此,该进程在其主线程运行时收到到了中断信号,并准备退出。首先,它需要等待后台线程运行结束。但是,这个线程对中断一无所知,这个线程只知道它需要在运行结束前完成 30 次迭代。
  • Python 在退出过程中使用的等待机制有一个规定,当收到第二个中断信号时,就会中止。这就是为什么第二个 Ctrl-C 会立即结束进程。所以我们看到了,线程是不能被杀死!在下面的章节中,将向展示 Python 中的两个方式,来使线程及时结束。

2. 使用守护进程

Daemon Threads

  • 在上面提到过,在 Python 退出之前,它会等待任何非守护线程的线程。而守护线程就是,一个不会阻止 Python 解释器退出的线程。
  • 如何使一个线程成为一个守护线程?所有的线程对象都有一个 daemon 属性,可以在启动线程之前将这个属性设置为 True,然后该线程就会被视为一个守护线程。下面是上面的示例应用程序,修改后守护线程版本:
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())  # do some work...      print(f'{i} iterations completed before exiting.')  th = threading.Thread(target=bg_thread)  th.daemon = True  th.start()  th.join() 
  • 再次运行它,并尝试中断它,发现第一个执行 Ctrl-C 后进程立即就退出了。
~ $ python x.py  1 of 30 iterations...  2 of 30 iterations...  3 of 30 iterations...  4 of 30 iterations...  5 of 30 iterations...  6 of 30 iterations...  ^CTraceback (most recent call last):    File "thread.py", line 15, in <module>      th.join()    File "/Users/mgrinberg/.pyenv/versions/3.8.6/lib/python3.8/threading.py", line 1011, in join      self._wait_for_tstate_lock()    File "/Users/mgrinberg/.pyenv/versions/3.8.6/lib/python3.8/threading.py", line 1027, in _wait_for_tstate_lock      elif lock.acquire(block, timeout):  KeyboardInterrupt 
  • 那么这个线程会发生什么呢?线程继续运行,就像什么都没发生一样,直到 Python 进程终止并返回到操作系统。这时,线程就不存在了。你可能认为这实际上是一种杀死线程的方法,但要考虑到以这种方式杀死线程,你必须同时杀死进程。

3. 使用事件对象

Python Events

  • 使用守护线程,是一种避免在多线程程序中处理意外中断的简单方法,但这是一种只在进程退出的特殊情况下才有效的技巧。不幸的是,有些时候,一个应用程序可能想结束一个线程而不必杀死自己。另外,有些线程可能需要在退出前执行清理工作,而守护线程则不允许这样操作。
  • 那么,还有什么其他选择呢?既然不可能强制线程结束,那么唯一的选择就是给它添加逻辑,让它在被要求退出时自愿退出。有多种方法都可以解决上述问题,但我特别喜欢的一种方法,就是使用一个 Event 对象。

Event 类是由 Python 标准库的线程模块提供,你可以通过实例化类来创建一个事件对象,就像下面这个样子:

exit_event = threading.Event() 
  • Event 对象可以处于两种状态之一: set 或 not set。当我们实例化创建之后,默认事件并没有被设置。
    • 若要将事件状态更改为 set,则可以调用 set()方法;
    • 要查明是否设置了事件,使用 is_set() 方法,设置了则返回 True;
    • 还可以使用 wait() 方法等待事件,等待操作阻塞直到设置事件(可以设置超时)
  • 其核心思路,就是在线程需要退出的时候设置事件。然后,线程需要经常地检查事件的状态(通常是在循环中),并在发现事件已经设置时处理自己的终止。对于上面显示的示例,一个好的解决方案是添加一个捕获 Ctrl-C 中断的信号处理程序,而不是突然退出,只需设置事件并让线程优雅地结束。
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() 
  • 如果你尝试中断这个版本的应用程序,一切看起来都会更好:
$ python thread.py  1 of 30 iterations...  2 of 30 iterations...  3 of 30 iterations...  4 of 30 iterations...  5 of 30 iterations...  6 of 30 iterations...  7 of 30 iterations...  ^C7 iterations completed before exiting. 
  • 需要注意的是,中断是如何被优雅地处理的,以及线程能够运行在循环之后出现的代码。如果当线程需要在退出之前,关闭文件句柄或数据库连接时,这种方式就非常有用了。其能够在线程退出之前,运行清理代码有时是必要的,以避免资源泄漏。我在上面提到过,event 对象也是可以等待的:
for i in range(1, 30):      print(f'{i} of 30 iterations...')      time.sleep(random.random())      if exit_event.is_set():          break 
  • 在每个迭代中,都有一个对 time.sleep() 的调用,这将阻塞线程。如果在线程 sleep 时设置了退出事件,那么它就不能检查事件的状态,因此在线程能够退出之前会有一个小的延迟。在这种情况下,如果有 sleep,使用 wait() 方法将 sleep 与 event 对象的检查结合起来会更有效:
for i in range(1, 30):       print(f'{i} of 30 iterations...')       if exit_event.wait(timeout=random.random()):           break          
  • 这个解决方案有效地为提供了一个可中断的 sleep,因为在线程停留在 wait() 调用的中间时设置了事件,那么等待将立即返回。

4. 总结陈述说明

Conclusion

  • 你知道 Python 中的 event 对象吗?它们是比较简单的同步原语之一,不仅可以用作退出信号,而且在线程需要等待某些外部条件发生的许多其他情况下也可以使用。

相关推荐

安全教育登录入口平台(安全教育登录入口平台官网)

122交通安全教育怎么登录:122交通网的注册方法是首先登录网址http://www.122.cn/,接着打开网页后,点击右上角的“个人登录”;其次进入邮箱注册,然后进入到注册页面,输入相关信息即可完...

大鱼吃小鱼经典版(大鱼吃小鱼经典版(经典版)官方版)

大鱼吃小鱼小鱼吃虾是于谦跟郭麒麟的《我的棒儿呢?》郭德纲说于思洋郭麒麟作诗的相声,最后郭麒麟做了一首,师傅躺在师母身上大鱼吃小鱼小鱼吃虾虾吃水水落石出师傅压师娘师娘压床床压地地动山摇。...

谷歌地球下载高清卫星地图(谷歌地球地图下载器)
  • 谷歌地球下载高清卫星地图(谷歌地球地图下载器)
  • 谷歌地球下载高清卫星地图(谷歌地球地图下载器)
  • 谷歌地球下载高清卫星地图(谷歌地球地图下载器)
  • 谷歌地球下载高清卫星地图(谷歌地球地图下载器)
哪个软件可以免费pdf转ppt(免费的pdf转ppt软件哪个好)
哪个软件可以免费pdf转ppt(免费的pdf转ppt软件哪个好)

要想将ppt免费转换为pdf的话,我们建议大家可以下一个那个wps,如果你是会员的话,可以注册为会员,这样的话,在wps里面的话,就可以免费将ppt呢转换为pdfpdf之后呢,我们就可以直接使用,不需要去直接不需要去另外保存,为什么格式转...

2026-02-04 09:03 off999

电信宽带测速官网入口(电信宽带测速官网入口app)

这个网站看看http://www.swok.cn/pcindex.jsp1.登录中国电信网上营业厅,宽带光纤,贴心服务,宽带测速2.下载第三方软件,如360等。进行在线测速进行宽带测速时,尽...

植物大战僵尸95版手机下载(植物大战僵尸95 版下载)

1可以在应用商店或者游戏平台上下载植物大战僵尸95版手机游戏。2下载教程:打开应用商店或者游戏平台,搜索“植物大战僵尸95版”,找到游戏后点击下载按钮,等待下载完成即可安装并开始游戏。3注意:确...

免费下载ppt成品的网站(ppt成品免费下载的网站有哪些)

1、Chuangkit(chuangkit.com)直达地址:chuangkit.com2、Woodo幻灯片(woodo.cn)直达链接:woodo.cn3、OfficePlus(officeplu...

2025世界杯赛程表(2025世界杯在哪个国家)

2022年卡塔尔世界杯赛程公布,全部比赛在卡塔尔境内8座球场举行,2022年,决赛阶段球队全部确定。揭幕战于当地时间11月20日19时进行,由东道主卡塔尔对阵厄瓜多尔,决赛于当地时间12月18日...

下载搜狐视频电视剧(搜狐电视剧下载安装)

搜狐视频APP下载好的视频想要导出到手机相册里方法如下1、打开手机搜狐视频软件,进入搜狐视频后我们点击右上角的“查找”,找到自已喜欢的视频。2、在“浏览器页面搜索”窗口中,输入要下载的视频的名称,然后...

pubg免费下载入口(pubg下载入口官方正版)
  • pubg免费下载入口(pubg下载入口官方正版)
  • pubg免费下载入口(pubg下载入口官方正版)
  • pubg免费下载入口(pubg下载入口官方正版)
  • pubg免费下载入口(pubg下载入口官方正版)
永久免费听歌网站(丫丫音乐网)

可以到《我爱音乐网》《好听音乐网》《一听音乐网》《YYMP3音乐网》还可以到《九天音乐网》永久免费听歌软件有酷狗音乐和天猫精灵,以前要跳舞经常要下载舞曲,我从QQ上找不到舞曲下载就从酷狗音乐上找,大多...

音乐格式转换mp3软件(音乐格式转换器免费版)

有两种方法:方法一在手机上操作:1、进入手机中的文件管理。2、在其中选择“音乐”,将显示出手机中的全部音乐。3、点击“全选”,选中所有音乐文件。4、点击屏幕右下方的省略号图标,在弹出菜单中选择“...

电子书txt下载(免费的最全的小说阅读器)

1.Z-library里面收录了近千万本电子书籍,需求量大。2.苦瓜书盘没有广告,不需要账号注册,使用起来非常简单,直接搜索预览下载即可。3.鸠摩搜书整体风格简洁清晰,书籍资源丰富。4.亚马逊图书书籍...

最好免费观看高清电影(播放免费的最好看的电影)

在目前的网上选择中,IMDb(互联网电影数据库)被认为是最全的电影网站之一。这个网站提供了各种类型的电影和电视节目的海量信息,包括剧情介绍、演员表、评价、评论等。其还提供了有关电影制作背后的详细信息,...

孤单枪手2简体中文版(孤单枪手2简体中文版官方下载)

要将《孤胆枪手2》游戏的征兵秘籍切换为中文,您可以按照以下步骤进行操作:首先,打开游戏设置选项,通常可以在游戏主菜单或游戏内部找到。然后,寻找语言选项或界面选项,点击进入。在语言选项中,选择中文作为游...

取消回复欢迎 发表评论: