91欧美超碰AV自拍|国产成年人性爱视频免费看|亚洲 日韩 欧美一厂二区入|人人看人人爽人人操aV|丝袜美腿视频一区二区在线看|人人操人人爽人人爱|婷婷五月天超碰|97色色欧美亚州A√|另类A√无码精品一级av|欧美特级日韩特级

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

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

馬哥Linux運維 ? 來源:Escape ? 作者:Escape ? 2021-11-17 10:02 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

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

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

1. 線程無法結(jié)束

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()
  • 使用下面命令來運行程序,在下面的程序運行中,當(dāng)跑到第7次迭代時,按下Ctrl-C來中斷程序,發(fā)現(xiàn)后臺運行的程序并沒有終止掉。而在第13次迭代時,再次按下Ctrl-C來中斷程序,發(fā)現(xiàn)程序真的退出了。

$ 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 有一些邏輯是會在進(jìn)程退出前運行的,專門用來等待任何沒有被配置為守護線程的后臺線程結(jié)束,然后再把控制權(quán)真正交給操作系統(tǒng)。因此,該進(jìn)程在其主線程運行時收到到了中斷信號,并準(zhǔn)備退出。首先,它需要等待后臺線程運行結(jié)束。但是,這個線程對中斷一無所知,這個線程只知道它需要在運行結(jié)束前完成 30次迭代。

  • Python 在退出過程中使用的等待機制有一個規(guī)定,當(dāng)收到第二個中斷信號時,就會中止。這就是為什么第二個 Ctrl-C 會立即結(jié)束進(jìn)程。所以我們看到了,線程是不能被殺死!在下面的章節(jié)中,將向展示 Python 中的兩個方式,來使線程及時結(jié)束。


2. 使用守護進(jìn)程

Daemon Threads

  • 在上面提到過,在Python退出之前,它會等待任何非守護線程的線程。而守護線程就是,一個不會阻止Python解釋器退出的線程。

  • 如何使一個線程成為一個守護線程?所有的線程對象都有一個daemon屬性,可以在啟動線程之前將這個屬性設(shè)置為True,然后該線程就會被視為一個守護線程。下面是上面的示例應(yīng)用程序,修改后守護線程版本:

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()
  • 再次運行它,并嘗試中斷它,發(fā)現(xiàn)第一個執(zhí)行Ctrl-C后進(jìn)程立即就退出了。

~ $ 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
  • 那么這個線程會發(fā)生什么呢?線程繼續(xù)運行,就像什么都沒發(fā)生一樣,直到Python進(jìn)程終止并返回到操作系統(tǒng)。這時,線程就不存在了。你可能認(rèn)為這實際上是一種殺死線程的方法,但要考慮到以這種方式殺死線程,你必須同時殺死進(jìn)程。


3. 使用事件對象

Python Events

  • 使用守護線程,是一種避免在多線程程序中處理意外中斷的簡單方法,但這是一種只在進(jìn)程退出的特殊情況下才有效的技巧。不幸的是,有些時候,一個應(yīng)用程序可能想結(jié)束一個線程而不必殺死自己。另外,有些線程可能需要在退出前執(zhí)行清理工作,而守護線程則不允許這樣操作。

  • 那么,還有什么其他選擇呢?既然不可能強制線程結(jié)束,那么唯一的選擇就是給它添加邏輯,讓它在被要求退出時自愿退出。有多種方法都可以解決上述問題,但我特別喜歡的一種方法,就是使用一個Event對象。

Event類是由Python標(biāo)準(zhǔn)庫的線程模塊提供,你可以通過實例化類來創(chuàng)建一個事件對象,就像下面這個樣子:

exit_event = threading.Event()
  • Event對象可以處于兩種狀態(tài)之一:setnot set。當(dāng)我們實例化創(chuàng)建之后,默認(rèn)事件并沒有被設(shè)置。

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

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

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

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

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()
  • 如果你嘗試中斷這個版本的應(yīng)用程序,一切看起來都會更好:

$ 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.
  • 需要注意的是,中斷是如何被優(yōu)雅地處理的,以及線程能夠運行在循環(huán)之后出現(xiàn)的代碼。如果當(dāng)線程需要在退出之前,關(guān)閉文件句柄或數(shù)據(jù)庫連接時,這種方式就非常有用了。其能夠在線程退出之前,運行清理代碼有時是必要的,以避免資源泄漏。我在上面提到過,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()的調(diào)用,這將阻塞線程。如果在線程sleep時設(shè)置了退出事件,那么它就不能檢查事件的狀態(tài),因此在線程能夠退出之前會有一個小的延遲。在這種情況下,如果有sleep,使用wait()方法將sleepevent對象的檢查結(jié)合起來會更有效:

   for i in range(1, 30):        print(f'{i} of 30 iterations...')        if exit_event.wait(timeout=random.random()):            break

  • 這個解決方案有效地為提供了一個可中斷的sleep,因為在線程停留在wait()調(diào)用的中間時設(shè)置了事件,那么等待將立即返回。


4. 總結(jié)陳述說明

Conclusion

  • 你知道Python中的event對象嗎?它們是比較簡單的同步原語之一,不僅可以用作退出信號,而且在線程需要等待某些外部條件發(fā)生的許多其他情況下也可以使用。

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

責(zé)任編輯:haq
聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • python
    +關(guān)注

    關(guān)注

    57

    文章

    4876

    瀏覽量

    90051
  • 線程
    +關(guān)注

    關(guān)注

    0

    文章

    509

    瀏覽量

    20829

原文標(biāo)題:如何殺死一個Python線程

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

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關(guān)推薦
    熱點推薦

    兩個RS485-Modbus主站如何通訊

    本產(chǎn)品能很好解決Master-1主站向模塊寫入數(shù)據(jù),Master-2主站讀取數(shù)據(jù);Master-2主站向模塊寫入數(shù)據(jù),Master-1主站讀取數(shù)據(jù)。由此解決兩個主站之間的互相讀通信難題。
    發(fā)表于 02-08 15:32 ?0次下載

    使用博圖(TIA Portal)監(jiān)控PROFINET從站通訊狀態(tài)的兩個方法

    如何使用博圖監(jiān)控Profinet從站通訊狀態(tài),這里有兩個方法供你選擇。 方法一 | 使用DeviceStates指令 創(chuàng)建全局?jǐn)?shù)據(jù)塊 博圖項目中,創(chuàng)建一全局?jǐn)?shù)據(jù)塊(DB),用于存儲
    的頭像 發(fā)表于 01-17 11:21 ?1243次閱讀
    使用博圖(TIA Portal)監(jiān)控PROFINET從站通訊狀態(tài)的<b class='flag-5'>兩個</b>方法

    曙光存儲連續(xù)斬獲兩個行業(yè)獎項

    近期,曙光存儲連續(xù)斬獲兩個行業(yè)獎項,自研技術(shù)產(chǎn)品國產(chǎn)突破、AI行業(yè)應(yīng)用等方面的成果獲得廣泛關(guān)注。
    的頭像 發(fā)表于 01-15 16:28 ?2508次閱讀

    解析Linux的進(jìn)程、線程和協(xié)程

    允許單個線程內(nèi)實現(xiàn)多個協(xié)程的并發(fā)執(zhí)行。協(xié)程執(zhí)行過程中可以主動掛起和恢復(fù),這使得編寫高效的異步代碼變得更加容易。協(xié)程通常用于處理I/O密集型任務(wù),能夠提高程序的響應(yīng)性能。 協(xié)程的特
    發(fā)表于 12-22 11:00

    FreeRtos 能否同時使用兩個 CPU?

    的情況下,CM0 更愿意專門用于管理外設(shè)。 - 是否有 CM0 和 CM4 中同時運行代碼的簡單示例或教程? - FreeRtos 能否同時使用兩個 CPU?
    發(fā)表于 11-11 08:28

    Python調(diào)用API教程

    兩個不同系統(tǒng)之間的信息交互。在這篇文章中,我們將詳細(xì)介紹Python調(diào)用API的方法和技巧。 一、用Requests庫發(fā)送HTTP請求 使用Python調(diào)用API的第一步是發(fā)送HTTP請求,通常
    的頭像 發(fā)表于 11-03 09:15 ?888次閱讀

    RTThread線程退出后rt_malloc動態(tài)創(chuàng)建的資源沒有釋放怎么解決?

    測試過程中,線程中用rt_malloc動態(tài)創(chuàng)建4KB的資源,在線程運行過程中用rt_thr
    發(fā)表于 10-13 07:06

    rtt中建兩個線程a和b,怎么確保線程a執(zhí)行完立刻切到線程b?

    怎么獲取從線程開始切換到切換完成用的總的CPU時鐘節(jié)拍數(shù)量?
    發(fā)表于 10-10 06:37

    硬件SPI兩個CS操作兩個norflash,怎么互斥操作兩個norflash?

    硬件SPI兩個CS操作兩個norflash,怎么互斥操作兩個norflash,有一norflash被模擬成U盤,會在中斷中操作spi。
    發(fā)表于 09-26 06:18

    基本半導(dǎo)體連獲兩個行業(yè)獎項

    近日,基本半導(dǎo)體憑借碳化硅模塊領(lǐng)域的突出表現(xiàn),連獲“國產(chǎn)SiC模塊TOP企業(yè)獎”和“年度優(yōu)秀功率器件產(chǎn)品獎”兩個行業(yè)獎項。
    的頭像 發(fā)表于 09-05 16:31 ?1098次閱讀

    【HZ-T536開發(fā)板免費體驗】—— linux創(chuàng)建線程

    自己的私有資源。 linux系統(tǒng)中,線程狀態(tài)通常反映了當(dāng)前線程的當(dāng)前活動和執(zhí)行階段。 主要分為: 1。運行轉(zhuǎn)態(tài) 2。阻塞轉(zhuǎn)態(tài) 3。終止狀態(tài) 如何區(qū)分單
    發(fā)表于 09-01 21:31

    如何使用 SPI 全雙工兩個 5LP MPU 之間連接 RAM?

    我需要將兩個 5LP MPU 連接在一起以鏡像兩個 5LP MPU 內(nèi)的 RAM。 我認(rèn)為這將是 DMA 的一功能,但我不確定如何實現(xiàn)該功能。 我的主 SPI 單元將向從屬 MPU 發(fā)送一
    發(fā)表于 07-15 06:20

    看到STM8L152用兩個IO用兩個或非門檢測兩個通斷,是什么原理呢?

    圖中兩個按鍵開關(guān)是兩個干簧管,為什么不直接對GND設(shè)計來檢測這個干簧管通斷呢? 這樣設(shè)計的原理是什么?
    發(fā)表于 06-12 06:25

    用于四頻 GSM / GPRS / EDGE 的 Tx-Rx FEM,帶兩個 Rx 交換機端口和雙頻 TD-SCDMA skyworksinc

    電子發(fā)燒友網(wǎng)為你提供()用于四頻 GSM / GPRS / EDGE 的 Tx-Rx FEM,帶兩個 Rx 交換機端口和雙頻 TD-SCDMA相關(guān)產(chǎn)品參數(shù)、數(shù)據(jù)手冊,更有用于四頻 GSM
    發(fā)表于 05-29 18:31
    <b class='flag-5'>用于</b>四頻 GSM / GPRS / EDGE 的 Tx-Rx FEM,帶<b class='flag-5'>兩個</b> Rx 交換機端口和雙頻 TD-SCDMA skyworksinc

    請問如何在Python中實現(xiàn)多線程與多進(jìn)程的協(xié)作?

    大家好!我最近在開發(fā)一Python項目時,需要同時處理多個任務(wù),且每個任務(wù)需要不同的計算資源。我想通過多線程和多進(jìn)程的組合來實現(xiàn)并發(fā),但遇到了一些問題。 具體來說,我有兩個任務(wù),一
    發(fā)表于 03-11 06:57