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

简介: 由于主线程卡死是子线程的阻塞状态造成的,可以通过以下两种方法解决:1. 处理子线程阻塞:引入超时控制,确保子线程在合理时间内完成任务,并在必要时修改子线程的阻塞状态,以避免主线程长时间等待。2. 销毁子线程:如果子线程在完成任务后不再需要重复使用,可以考虑在结束时直接销毁该线程,以避免阻塞主线程。这两种方法可以有效避免主线程因子线程阻塞而卡死的问题。

问题背景

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

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

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


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


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


以下是简化后的代码:

 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

相关文章
|
1月前
|
人工智能 开发者 Python
python读取word文档 | AI应用开发
在RAG系统中,构建知识库时需读取多种外部文档,其中Word文档较为常见。本文介绍如何使用`python-docx`库读取Word文档(.docx格式)中的标题、段落、表格和图片等内容。首先通过`pip install python-docx`安装库,然后利用提供的接口提取所需信息。尽管该库功能强大,但在识别标题样式时需自定义逻辑,并且仅提供图片的URI而非直接加载。示例代码展示了读取文本、识别标题、读取表格及获取图片URI的方法。【10月更文挑战第2天】
72 2
|
3月前
|
Kubernetes 持续交付 Docker
Python进行容器化应用开发
【8月更文挑战第13天】随着云计算和微服务架构的发展,容器化已成为现代应用开发的关键部分。Docker和Kubernetes是最流行的容器化工具。本文通过Python示例展示如何构建、运行容器化应用,并使用Kubernetes进行部署。首先介绍如何用Docker容器化一个简单的Flask应用,接着演示如何通过Kubernetes YAML文件定义和管理应用部署和服务。最后,探讨了使用Python与Docker及Kubernetes集成的最佳实践,包括自动化测试、持续集成、微服务架构和容器编排。
27 1
记一次 Python 应用开发频繁假死的问题
但是,在测试时,却发现了问题: 当我点击暂停任务后,此时子线程被阻塞。如果我这个时候点击停止,那么就会任务结束。 之后,如果我再点击开始运行,整个应用就会卡死,非常离谱。
|
4月前
|
开发者 Python
python flask 简单应用开发
python flask 简单应用开发
34 0
|
6月前
|
人工智能 Python
【AI大模型应用开发】【LangChain系列】实战案例1:用LangChain写Python代码并执行来生成答案
【AI大模型应用开发】【LangChain系列】实战案例1:用LangChain写Python代码并执行来生成答案
386 0
|
6月前
|
机器学习/深度学习 人工智能 算法
【AI大模型应用开发】【补充知识】文本向量化与向量相似度(含Python代码)
【AI大模型应用开发】【补充知识】文本向量化与向量相似度(含Python代码)
111 0
|
6月前
|
开发框架 安全 数据库
使用Python中的Django框架进行Web应用开发
【4月更文挑战第15天】Django,作为Python中一个久负盛名的Web开发框架,以其强大的功能、优雅的设计和高效的开发流程,赢得了广大开发者的青睐。无论是初创企业还是大型组织,Django都能帮助开发者快速构建出稳定、安全的Web应用。本文将深入探讨Django框架的核心特性、使用方法以及在实际开发中的应用。
|
6月前
|
前端开发 数据挖掘 API
使用Python中的Flask框架进行Web应用开发
【4月更文挑战第15天】在Python的Web开发领域,Flask是一个备受欢迎的轻量级Web框架。它简洁、灵活且易于扩展,使得开发者能够快速地构建出高质量的Web应用。本文将深入探讨Flask框架的核心特性、使用方法以及在实际开发中的应用。
|
XML JSON 缓存
"Python与API:构建灵活强大的数据交互与应用开发平台"
在当今数字化时代,数据交互和应用开发已成为各行业发展的关键。而Python作为一种简洁、易学且功能强大的编程语言,以其丰富的库和模块凭借得天独厚的优势成为了开发人员的首选。同时,通过与API(应用程序接口)的结合,Python实现了无限可能,为构建灵活强大的数据交互和应用开发平台提供了有力支持。
138 0
|
XML JSON 缓存
Python如何利用API进行数据交互和应用开发
在当今数字化时代,数据交互变得越来越重要,而应用程序接口(API)是实现数据交互的关键。Python作为一种功能强大的编程语言,在使用API进行数据交互和应用开发方面表现出色。本文将介绍一些基本概念和步骤,帮助您理解Python如何利用API进行数据交互和应用开发。
139 0