Python應用開發(fā)頻繁假死的問題分析及解決
問題背景
最近在開發(fā)一款自動化的應用,其中有一個自動化任務會由下面這三個按鈕控制:
邏輯也很簡單,我大概畫下圖就是這樣的:
但是,在測試時,卻發(fā)現(xiàn)了問題:
當我點擊暫停任務后,此時子線程被阻塞。如果我這個時候點擊停止,那么就會任務結(jié)束。
之后,如果我再點擊開始運行,整個應用就會卡死,非常離譜。
以下是簡化后的代碼:
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("開始執(zhí)行") 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() # 執(zhí)行任務 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()
按照代碼邏輯,我期待的結(jié)果是點擊停止后,再次點擊開始就可以開始重新運行,但是,雖然第一次顯示停止了,可如果想再次開始,程序就會卡住不動了,下面為測試時輸出的結(jié)果:
我點擊了開始 任務開始 開始執(zhí)行 是否需要暫停:False do something: 0 我點擊了暫停 是否需要暫停:True 我點擊了停止 成功停止 # 然后在這里卡死
昨天下午一直在代碼中斷點找原因,搞了半天,都沒能解決,下班前我甚至都在懷疑是不是 Python 代碼的問題,想去看看源碼找原因了。
找出原因
不過簡化代碼,確實比較有效,當我把整個流程簡化成上面的代碼,就比較方便找出問題出在哪里了。
是因為,當我點擊“暫停”后,子線程進入阻塞狀態(tài)。當執(zhí)行“停止”操作時,使用了 self._thread.join()
,這會導致主線程阻塞,直到子線程 self._thread
完成。然而,如果子線程因阻塞狀態(tài)無法完成,就會導致主線程永久等待,結(jié)果是主線程卡死。
后面我看了下我們實際開發(fā)的應用代碼,問題要更復雜點,但說到底,都是線程阻塞狀態(tài)沒有得到正確處理,導致的卡死。
解決辦法
由于主線程卡死是子線程的阻塞狀態(tài)造成的,可以通過以下兩種方法解決:
- 處理子線程阻塞:引入超時控制,確保子線程在合理時間內(nèi)完成任務,并在必要時修改子線程的阻塞狀態(tài),以避免主線程長時間等待。
- 銷毀子線程:如果子線程在完成任務后不再需要重復使用,可以考慮在結(jié)束時直接銷毀該線程,以避免阻塞主線程。
這兩種方法可以有效避免主線程因子線程阻塞而卡死的問題。
以上就是Python應用開發(fā)頻繁假死的問題分析及解決的詳細內(nèi)容,更多關于Python應用開發(fā)假死的資料請關注腳本之家其它相關文章!
相關文章
Python利用PyVista進行mesh的色彩映射的實現(xiàn)
這篇文章主要介紹了Python利用PyVista進行mesh的色彩映射的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2021-04-04移除Selenium中window.navigator.webdriver值
這篇文章主要為大家介紹了如何正確的移除Selenium中window.navigator.webdriver的值方法步驟,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-06-06Pandas數(shù)據(jù)類型轉(zhuǎn)換df.astype()及數(shù)據(jù)類型查看df.dtypes的使用
Python,numpy都有自己的一套數(shù)據(jù)格式,本文主要介紹了Pandas數(shù)據(jù)類型轉(zhuǎn)換df.astype()及數(shù)據(jù)類型查看df.dtypes的使用,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2022-07-07Python文件操作和數(shù)據(jù)格式詳解(簡單簡潔)
文本處理是腳本語言的強項,下面這篇文章主要給大家介紹了關于Python文件操作和數(shù)據(jù)格式的相關資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下2022-05-05