吴忠躺衫网络科技有限公司

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

在Python中用于終止線程的兩個選項

馬哥Linux運維 ? 來源:Escape ? 作者:Escape ? 2021-11-17 10:02 ? 次閱讀

我經常被問到如何殺死一個后臺線程,這個問題的答案讓很多人不開心: 線程是殺不死的。在本文中,我將向您展示Python中用于終止線程的兩個選項。

如果我們是一個好奇寶寶的話,可能會遇到這樣一個問題,就是:如何殺死一個Python的后臺線程呢?我們可能嘗試解決這個問題,卻發現線程是殺不死的。而本文中將展示,在Python中用于終止線程的兩個方式。

1. 線程無法結束

A Threaded Example

  • 下面是一個簡單的,多線程的示例代碼。

import randomimport threadingimport 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.py1 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     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):KeyboardInterrupt8 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: 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 randomimport threadingimport 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 = Trueth.start()th.join()
  • 再次運行它,并嘗試中斷它,發現第一個執行Ctrl-C后進程立即就退出了。

~ $ python x.py1 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     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對象可以處于兩種狀態之一:setnot set。當我們實例化創建之后,默認事件并沒有被設置。

    • 若要將事件狀態更改為set,則可以調用set()方法;

    • 要查明是否設置了事件,使用is_set()方法,設置了則返回True;

    • 還可以使用wait()方法等待事件,等待操作阻塞直到設置事件(可以設置超時)

  • 其核心思路,就是在線程需要退出的時候設置事件。然后,線程需要經常地檢查事件的狀態(通常是在循環中),并在發現事件已經設置時處理自己的終止。對于上面顯示的示例,一個好的解決方案是添加一個捕獲Ctrl-C中斷的信號處理程序,而不是突然退出,只需設置事件并讓線程優雅地結束。

import randomimport signalimport threadingimport 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.py1 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()方法將sleepevent對象的檢查結合起來會更有效:

   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對象嗎?它們是比較簡單的同步原語之一,不僅可以用作退出信號,而且在線程需要等待某些外部條件發生的許多其他情況下也可以使用。

原文鏈接:https://www.escapelife.site/posts/558f583c.html

責任編輯:haq
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • python
    +關注

    關注

    56

    文章

    4807

    瀏覽量

    85040
  • 線程
    +關注

    關注

    0

    文章

    505

    瀏覽量

    19758

原文標題:如何殺死一個Python線程

文章出處:【微信號:magedu-Linux,微信公眾號:馬哥Linux運維】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    Python中多線程和多進程的區別

    Python作為一種高級編程語言,提供了多種并發編程的方式,其中多線程與多進程是最常見的種方式之一。本文中,我們將探討Python中多
    的頭像 發表于 10-23 11:48 ?495次閱讀
    <b class='flag-5'>Python</b>中多<b class='flag-5'>線程</b>和多進程的區別

    單相電機兩個繞組都在定子上嗎

    單相電機的兩個繞組,即起動線圈(或稱為輔助繞組、副繞組)和運行線圈(或稱為主繞組),都位于定子上 。這兩個繞組電機中起著關鍵作用,共同協作以產生旋轉磁場,從而使電機能夠運轉。 單相電機通常由一
    的頭像 發表于 09-03 15:10 ?1072次閱讀

    ad如何設置兩個元器件的距離

    Altium Designer(簡稱AD)中設置兩個元器件之間的距離,主要是通過設置元器件間的安全間距(Clearance)規則來實現的。這個規則定義了元器件之間、元器件與走線之間以及其他設計元素
    的頭像 發表于 09-02 15:31 ?8509次閱讀

    功放機AB兩個聲道輸出怎么接

    功放機AB兩個聲道輸出的接線方式,主要取決于您想要實現的音頻效果以及音箱的配置。以下將詳細介紹幾種常見的接線方式,以及它們各自的特點和適用場景。 一、基礎接線方式 大多數情況下,功放機的AB兩個
    的頭像 發表于 08-23 10:40 ?4091次閱讀

    觸發器的兩個穩定狀態分別是什么

    觸發器作為數字電路中的基本邏輯單元,具有兩個穩定狀態,這兩個狀態通常用于表示二進制數碼中的0和1。
    的頭像 發表于 08-12 11:01 ?1638次閱讀

    雙穩態電路的兩個穩定狀態是什么

    雙穩態電路是一種具有兩個穩定狀態的電子電路,廣泛應用于數字電路、通信系統、存儲器等領域。 雙穩態電路的基本概念 雙穩態電路是一種具有兩個穩定狀態的電路,即在沒有外部輸入信號的情況下,電路可以保持
    的頭像 發表于 08-11 15:00 ?1740次閱讀

    雙穩態觸發器的兩個基本性質是什么

    雙穩態觸發器(Bistable Trigger)是一種具有兩個穩定狀態的邏輯電路,廣泛應用于數字電路設計中。它具有兩個基本性質:記憶性和切換性。 一、雙穩態觸發器的基本概念 1.1 雙穩態觸發器
    的頭像 發表于 08-11 10:08 ?824次閱讀

    兩個PLC之間如何交互信號

    工業自動化系統中,PLC(Programmable Logic Controller,可編程邏輯控制器)是核心的控制設備。許多復雜的應用場景中,需要兩個或多個PLC之間進行信號交互,以實現更高
    的頭像 發表于 06-14 16:57 ?4868次閱讀

    鴻蒙開發:【線程模型】

    管理其他線程的ArkTS引擎實例,例如使用TaskPool(任務池)創建任務或取消任務、啟動和終止Worker線程
    的頭像 發表于 06-13 16:38 ?459次閱讀
    鴻蒙開發:【<b class='flag-5'>線程</b>模型】

    兩個銅片可以形成原電池嗎

    兩個銅片本身不能形成原電池,因為原電池的工作原理依賴于兩個不同電位的電極材料之間的氧化還原反應。
    的頭像 發表于 05-21 16:23 ?1165次閱讀

    為什么交流電橋中至少需要兩個可調參數?

    交流電橋的測量中,至少需要兩個可調參數的原因與電橋的工作原理、測量的準確性以及校準過程有關。
    的頭像 發表于 05-15 17:49 ?1998次閱讀

    原電池中的兩個電極能是相同的嗎?

    原電池的設計和運作中,兩個電極是否可以相同,這取決于電池的類型和所需的電化學反應。
    的頭像 發表于 04-26 17:32 ?2769次閱讀

    python中5種線程鎖盤點

    線程安全是多線程或多進程編程中的一概念,擁有共享數據的多條線程并行執行的程序中,線程安全的代
    發表于 03-07 11:08 ?1671次閱讀
    <b class='flag-5'>python</b>中5種<b class='flag-5'>線程</b>鎖盤點

    arcgis中如何關聯兩個屬性表

    ArcGIS中,關聯兩個屬性表是一重要的操作,可以通過此操作將兩個表中的數據關聯起來,以便進行分析和查詢。下面是詳細介紹如何在ArcGIS中實現屬性表的關聯。 首先,我們需要明確
    的頭像 發表于 02-25 11:01 ?4475次閱讀

    求助,關于FX3的兩個使用問題求解

    如題,咨詢FX3的兩個使用問題: 1,F1F模式下,燒寫成功后,WIN10無法識別設備,切換到0F1,燒寫成功后,WIN10同樣無法識別設備,所以現在我的板子只能使用USB引導了,燒寫到RAM可以
    發表于 02-22 07:16
    正品百家乐网站| 请问下百家乐去哪个娱乐城玩最好呢| 风水做生意店铺的门| 百家乐官网高手论坛| 百家乐官网五局八星| 即时比分直播| 大发888娱乐城dafa888dafa8| 无锡百家乐的玩法技巧和规则 | 高额德州扑克第七季| 威尼斯人娱乐信誉| 赌场百家乐图片| 赌博百家乐经验网| 太阳会百家乐现金网| 蓝宝石百家乐官网娱乐城| 二代百家乐官网破解| 百家乐官网投注方式| 曲麻莱县| 大赢家网上娱乐| 大发888怎么赢钱| 澳门百家乐群代理| 二爷百家乐的玩法技巧和规则| 百家乐改单软件| 百家乐娱乐城备用网址| 富易堂百家乐娱乐城| 百家乐另类投注法| 百家乐官网群必胜打朽法| 爱婴百家乐官网的玩法技巧和规则| 澳门百家乐官网规律星期娱乐城博彩| 百家乐官网扑克桌布| 百家乐官网玩法说明| 易发娱乐场| 云鼎娱乐城优惠| e娱乐城棋牌| 大发888娱乐在线| 皇冠现金网安全吗| 大发888游戏平台hg dafa888 gw| 大发888常见断续| 大发888老虎机下载免费| 大发888线上投注| 德州扑克 技巧| 大发888 方管下载|