记一次 Python 应用开发频繁假死的问题

简介: 但是,在测试时,却发现了问题:当我点击暂停任务后,此时子线程被阻塞。如果我这个时候点击停止,那么就会任务结束。之后,如果我再点击开始运行,整个应用就会卡死,非常离谱。

问题背景

最近在开发一款自动化的应用,其中有一个自动化任务会由下面这三个按钮控制:

1723444406671.jpg

逻辑也很简单,我大概画下图就是这样的:

1723444417286.jpg

但是,在测试时,却发现了问题:


当我点击暂停任务后,此时子线程被阻塞。如果我这个时候点击停止,那么就会任务结束。


之后,如果我再点击开始运行,整个应用就会卡死,非常离谱。


以下是简化后的代码:

import threading
 import time
 from sample_singleton import singleton
 @singleton
 class TestThreadingEvent:
     def __init__(self):
         self._stop_event = threading.Event()
         self._pause_event = threading.Event()
         self._thread = None
     def set_stop(self):
         self._stop_event.set()
     def set_pause(self):
         self._pause_event.set()
     def start(self):
         print("任务开始")
         self._stop_event.clear()
         self._pause_event.set()
         print("开始执行")
         self._thread = threading.Thread(target=self._run)
         self._thread.start()
     def _run(self):
         count = 0
         while True:
             if self._stop_event.is_set():
                 print("任务被成功停止")
                 return
             print(f"是否需要暂停:{not self._pause_event.is_set()}")
             self._pause_event.wait()
             # 执行任务
             print(f"do something: {count}")
             time.sleep(1)
             count += 1
     def pause(self):
         print("点击了暂停")
         self._pause_event.clear()
         time.sleep(2)
     def stop(self):
         print("点击了停止")
         self._stop_event.set()
         print("成功停止")
         if self._thread is not None:
             self._thread.join()  # 确保线程终止
 print("我点击了开始")
 singletonA = TestThreadingEvent()
 singletonA.start()
 singletonA.pause()
 print("我点击了停止")
 singletonA.stop()
 print("我再次点击了开始")
 singletonA.start()

按照代码逻辑,我期待的结果是点击停止后,再次点击开始就可以开始重新运行,但是,虽然第一次显示停止了,可如果想再次开始,程序就会卡住不动了,下面为测试时输出的结果:

我点击了开始
 任务开始
 开始执行
 是否需要暂停:False
 do something: 0
 我点击了暂停
 是否需要暂停:True
 我点击了停止
 成功停止
 # 然后在这里卡死

昨天下午一直在代码中断点找原因,搞了半天,都没能解决,下班前我甚至都在怀疑是不是 Python 代码的问题,想去看看源码找原因了。

找出原因

不过简化代码,确实比较有效,当我把整个流程简化成上面的代码,就比较方便找出问题出在哪里了。


是因为,当我点击“暂停”后,子线程进入阻塞状态。当执行“停止”操作时,使用了 self._thread.join(),这会导致主线程阻塞,直到子线程 self._thread 完成。然而,如果子线程因阻塞状态无法完成,就会导致主线程永久等待,结果是主线程卡死。


后面我看了下我们实际开发的应用代码,问题要更复杂点,但说到底,都是线程阻塞状态没有得到正确处理,导致的卡死。

解决办法

由于主线程卡死是子线程的阻塞状态造成的,可以通过以下两种方法解决:

  1. 处理子线程阻塞:引入超时控制,确保子线程在合理时间内完成任务,并在必要时修改子线程的阻塞状态,以避免主线程长时间等待。
  2. 销毁子线程:如果子线程在完成任务后不再需要重复使用,可以考虑在结束时直接销毁该线程,以避免阻塞主线程。


这两种方法可以有效避免主线程因子线程阻塞而卡死的问题。

作者:设计笔记

链接:https://juejin.cn/post/7398046313084321811

相关文章
|
测试技术
常见测试术语
提供和维护一个主测试计划( Master Testing Plan ),包含所有预期的测试活动和测试交付物。综合的测试计划应当结合总的项目和程序开发计划,并保证资源和责任在项目中尽可能早的被了解和分配。
2118 0
|
机器学习/深度学习 人工智能 供应链
策略篇2:货品运营怎么做? 基于数据智能的货品运营产品Quick Stock | 《零售数据中台通关指南》
本篇介绍了针对数字化应用方向的未来蓝图和阿里云端到端的智能货品解决方案(Quick Stock),包括从选址/选品,新品创新,需求预测/库存计划/供应链执行等。
策略篇2:货品运营怎么做? 基于数据智能的货品运营产品Quick Stock  | 《零售数据中台通关指南》
|
并行计算 TensorFlow 调度
推荐场景GPU优化的探索与实践:CUDA Graph与多流并行的比较与分析
RTP 系统(即 Rank Service),是一个面向搜索和推荐的 ranking 需求,支持多种模型的在线 inference 服务,是阿里智能引擎团队沉淀多年的技术产品。今年,团队在推荐场景的GPU性能优化上又做了新尝试——在RTP上集成了Multi Stream,改变了TensorFlow的单流机制,让多流的执行并行,作为增加GPU并行度的另一种选择。本文详细介绍与比较了CUDA Graph与多流并行这两个方案,以及团队的实践成果与心得。
|
数据采集 数据可视化 搜索推荐
如何在 FLowUs 和 Notion 等笔记软件中建立书籍管理系统?
为什么需要建立书籍管理系统? 在日常的学习和生活中,很多人喜欢建立一些电子书籍管理系统。其中,主要办法有三个:其一,使用当当、微信读书等阅读平台建立电子书单;其二,利用豆瓣这个书影音站点建立电子书单。
1165 0
如何在 FLowUs 和 Notion 等笔记软件中建立书籍管理系统?
|
存储 算法 芯片
基于单片机的音频信号分析仪毕业设计
基于单片机的音频信号分析仪毕业设计
471 0
基于单片机的音频信号分析仪毕业设计
有哪些CAD软件支持(国产操作系统)麒麟操作系统
CAD梦想画图是由成都梦想凯德科技自主研发的轻量级CAD软件,专为国产操作系统如麒麟、统信设计。支持AutoCAD所有版本的dwg二维图纸,具备精准显示、测量、标注、绘图修改、文字查找及批注等功能,操作流畅,无需安装字体。用户可通过应用商店轻松安装,适合新手和专业人士使用。
|
消息中间件 Java Kafka
使用Spring Boot和Kafka实现高效消息队列
使用Spring Boot和Kafka实现高效消息队列
|
8月前
|
人工智能 Unix API
50_选择模型:开源vs闭源
在大型语言模型(LLM)技术快速发展的今天,企业和开发者面临着一个关键决策:是选择开源LLM模型还是闭源LLM服务?这个选择直接影响到项目的成本结构、开发灵活性、数据安全性以及长期战略规划。随着2025年LLM技术的进一步成熟,开源与闭源模型之间的竞争格局也发生了显著变化。
1009 0
|
存储 自然语言处理 固态存储
初次使用 Elasticsearch 遇多种分词难题?那是你没掌握这些原理
命名有包含搜索关键词的文档,但结果却没有?存进去的文档被分成哪些词(term)了?自定义分词规则,但感觉好麻烦呢,无从下手?
6389 0
初次使用 Elasticsearch 遇多种分词难题?那是你没掌握这些原理
|
移动开发 前端开发 JavaScript
Web实训项目--网页设计(附源码)
Web实训项目--网页设计(附源码)
954 0