成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

如何殺死一個Python線程

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

[[435048]]

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

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

1. 線程無法結束

A Threaded Example

  •  下面是一個簡單的,多線程的示例代碼。 
  1. import random  
  2. import threading  
  3. import time  
  4. def bg_thread():  
  5.     for i in range(1, 30):  
  6.         print(f'{i} of 30 iterations...')  
  7.         time.sleep(random.random())  # do some work...  
  8.     print(f'{i} iterations completed before exiting.')  
  9. th = threading.Thread(target=bg_thread 
  10. th.start()  
  11. th.join() 
  •  使用下面命令來運行程序,在下面的程序運行中,當跑到第 7 次迭代時,按下 Ctrl-C 來中斷程序,發現后臺運行的程序并沒有終止掉。而在第 13 次迭代時,再次按下 Ctrl-C 來中斷程序,發現程序真的退出了。 
  1. $ python thread.py  
  2. 1 of 30 iterations...  
  3. 2 of 30 iterations...  
  4. 3 of 30 iterations...  
  5. 4 of 30 iterations...  
  6. 5 of 30 iterations...  
  7. 6 of 30 iterations...  
  8. 7 of 30 iterations...  
  9. ^CTraceback (most recent call last):  
  10.   File "thread.py", line 14, in <module>  
  11.     th.join()  
  12.   File "/Users/mgrinberg/.pyenv/versions/3.8.6/lib/python3.8/threading.py", line 1011, in join  
  13.     self._wait_for_tstate_lock()  
  14.   File "/Users/mgrinberg/.pyenv/versions/3.8.6/lib/python3.8/threading.py", line 1027, in _wait_for_tstate_lock  
  15.     elif lock.acquire(block, timeout):  
  16. KeyboardInterrupt  
  17. 8 of 30 iterations...  
  18. 9 of 30 iterations...  
  19. 10 of 30 iterations...  
  20. 11 of 30 iterations...  
  21. 12 of 30 iterations...  
  22. 13 of 30 iterations...  
  23. ^CException ignored in: <module 'threading' from '/Users/mgrinberg/.pyenv/versions/3.8.6/lib/python3.8/threading.py'>  
  24. Traceback (most recent call last):  
  25.   File "/Users/mgrinberg/.pyenv/versions/3.8.6/lib/python3.8/threading.py", line 1388, in _shutdown  
  26.     lock.acquire()  
  27. KeyboardInterrupt: 
  •  這很奇怪,不是嗎?究其原因是,Python 有一些邏輯是會在進程退出前運行的,專門用來等待任何沒有被配置為守護線程的后臺線程結束,然后再把控制權真正交給操作系統。因此,該進程在其主線程運行時收到到了中斷信號,并準備退出。首先,它需要等待后臺線程運行結束。但是,這個線程對中斷一無所知,這個線程只知道它需要在運行結束前完成 30 次迭代。
  •  Python 在退出過程中使用的等待機制有一個規定,當收到第二個中斷信號時,就會中止。這就是為什么第二個 Ctrl-C 會立即結束進程。所以我們看到了,線程是不能被殺死!在下面的章節中,將向展示 Python 中的兩個方式,來使線程及時結束。

2. 使用守護進程

Daemon Threads

  •  在上面提到過,在 Python 退出之前,它會等待任何非守護線程的線程。而守護線程就是,一個不會阻止 Python 解釋器退出的線程。
  •  如何使一個線程成為一個守護線程?所有的線程對象都有一個 daemon 屬性,可以在啟動線程之前將這個屬性設置為 True,然后該線程就會被視為一個守護線程。下面是上面的示例應用程序,修改后守護線程版本: 
  1. import random  
  2. import threading  
  3. import time  
  4. def bg_thread():  
  5.     for i in range(1, 30):  
  6.         print(f'{i} of 30 iterations...')  
  7.         time.sleep(random.random())  # do some work...  
  8.     print(f'{i} iterations completed before exiting.')  
  9. th = threading.Thread(target=bg_thread 
  10. th.daemon = True  
  11. th.start()  
  12. th.join() 
  •  再次運行它,并嘗試中斷它,發現第一個執行 Ctrl-C 后進程立即就退出了。 
  1. ~ $ python x.py  
  2. 1 of 30 iterations...  
  3. 2 of 30 iterations...  
  4. 3 of 30 iterations...  
  5. 4 of 30 iterations...  
  6. 5 of 30 iterations...  
  7. 6 of 30 iterations...  
  8. ^CTraceback (most recent call last):  
  9.   File "thread.py", line 15, in <module>  
  10.     th.join()  
  11.   File "/Users/mgrinberg/.pyenv/versions/3.8.6/lib/python3.8/threading.py", line 1011, in join  
  12.     self._wait_for_tstate_lock()  
  13.   File "/Users/mgrinberg/.pyenv/versions/3.8.6/lib/python3.8/threading.py", line 1027, in _wait_for_tstate_lock  
  14.     elif lock.acquire(block, timeout):  
  15. KeyboardInterrupt 
  •  那么這個線程會發生什么呢?線程繼續運行,就像什么都沒發生一樣,直到 Python 進程終止并返回到操作系統。這時,線程就不存在了。你可能認為這實際上是一種殺死線程的方法,但要考慮到以這種方式殺死線程,你必須同時殺死進程。

3. 使用事件對象

Python Events

  •  使用守護線程,是一種避免在多線程程序中處理意外中斷的簡單方法,但這是一種只在進程退出的特殊情況下才有效的技巧。不幸的是,有些時候,一個應用程序可能想結束一個線程而不必殺死自己。另外,有些線程可能需要在退出前執行清理工作,而守護線程則不允許這樣操作。
  •  那么,還有什么其他選擇呢?既然不可能強制線程結束,那么唯一的選擇就是給它添加邏輯,讓它在被要求退出時自愿退出。有多種方法都可以解決上述問題,但我特別喜歡的一種方法,就是使用一個 Event 對象。

Event 類是由 Python 標準庫的線程模塊提供,你可以通過實例化類來創建一個事件對象,就像下面這個樣子: 

  1. exit_event = threading.Event() 
  •  Event 對象可以處于兩種狀態之一: set 或 not set。當我們實例化創建之后,默認事件并沒有被設置。
    •   若要將事件狀態更改為 set,則可以調用 set()方法;
    •   要查明是否設置了事件,使用 is_set() 方法,設置了則返回 True;
    •   還可以使用 wait() 方法等待事件,等待操作阻塞直到設置事件(可以設置超時)
  •  其核心思路,就是在線程需要退出的時候設置事件。然后,線程需要經常地檢查事件的狀態(通常是在循環中),并在發現事件已經設置時處理自己的終止。對于上面顯示的示例,一個好的解決方案是添加一個捕獲 Ctrl-C 中斷的信號處理程序,而不是突然退出,只需設置事件并讓線程優雅地結束。 
  1. import random  
  2. import signal  
  3. import threading  
  4. import time  
  5. exit_event = threading.Event()  
  6. def bg_thread():  
  7.     for i in range(1, 30):  
  8.         print(f'{i} of 30 iterations...')  
  9.         time.sleep(random.random())  # do some work...  
  10.         if exit_event.is_set():  
  11.             break 
  12.      print(f'{i} iterations completed before exiting.')    
  13. def signal_handler(signum, frame):  
  14.     exit_event.set()  
  15. signal.signal(signal.SIGINT, signal_handler)  
  16. th = threading.Thread(target=bg_thread 
  17. th.start()  
  18. th.join() 
  •  如果你嘗試中斷這個版本的應用程序,一切看起來都會更好: 
  1. $ python thread.py  
  2. 1 of 30 iterations...  
  3. 2 of 30 iterations...  
  4. 3 of 30 iterations...  
  5. 4 of 30 iterations...  
  6. 5 of 30 iterations...  
  7. 6 of 30 iterations...  
  8. 7 of 30 iterations...  
  9. ^C7 iterations completed before exiting. 
  •  需要注意的是,中斷是如何被優雅地處理的,以及線程能夠運行在循環之后出現的代碼。如果當線程需要在退出之前,關閉文件句柄或數據庫連接時,這種方式就非常有用了。其能夠在線程退出之前,運行清理代碼有時是必要的,以避免資源泄漏。我在上面提到過,event 對象也是可以等待的: 
  1. for i in range(1, 30):  
  2.     print(f'{i} of 30 iterations...')  
  3.     time.sleep(random.random())  
  4.     if exit_event.is_set():  
  5.         break 
  •  在每個迭代中,都有一個對 time.sleep() 的調用,這將阻塞線程。如果在線程 sleep 時設置了退出事件,那么它就不能檢查事件的狀態,因此在線程能夠退出之前會有一個小的延遲。在這種情況下,如果有 sleep,使用 wait() 方法將 sleep 與 event 對象的檢查結合起來會更有效: 
  1. for i in range(1, 30):  
  2.      print(f'{i} of 30 iterations...')  
  3.      if exit_event.wait(timeout=random.random()):  
  4.          break          
  •  這個解決方案有效地為提供了一個可中斷的 sleep,因為在線程停留在 wait() 調用的中間時設置了事件,那么等待將立即返回。

4. 總結陳述說明

Conclusion

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

 

責任編輯:龐桂玉 來源: 馬哥Linux運維
相關推薦

2021-11-01 12:13:53

Linux僵尸進程

2022-03-09 09:43:01

工具類線程項目

2022-12-12 11:14:06

LinuxID

2025-01-26 09:35:45

2017-05-27 14:45:04

Linux命令進程

2022-03-07 05:53:41

線程CPU代碼

2021-03-29 08:47:24

線程面試官線程池

2020-10-27 13:24:35

線程池系統模型

2015-09-17 13:26:56

線程數進程Linux

2018-03-23 10:00:34

PythonTensorFlow神經網絡

2021-03-05 10:13:45

Python 開發編程語言

2022-09-07 10:20:05

Python裝飾類

2019-08-13 09:31:53

瀏覽器 Chrome Google

2016-12-15 08:54:52

線程sessionopenSession

2020-12-21 06:09:39

線程Java對象

2010-02-23 15:52:14

Python編輯器

2023-09-05 09:00:00

工具Python抄襲檢測系統

2023-09-04 08:08:59

2013-04-25 09:55:21

進程線程

2018-06-05 15:41:22

進程線程協程
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产成人自拍一区 | 成年人视频在线免费观看 | 欧美综合一区 | 国产精品久久久久久久久久三级 | 久久99精品久久久久久 | 久久99精品国产自在现线小黄鸭 | 日韩一区二区久久 | 国产精品日韩高清伦字幕搜索 | 91精品久久久久久久久 | 在线高清免费观看视频 | 亚洲高清免费视频 | 亚洲日本欧美日韩高观看 | 国产精品久久久久久久久久久久冷 | 日日操夜夜操视频 | 久久久久久综合 | 亚洲自拍一区在线观看 | 91精品在线观看入口 | 中文字幕亚洲视频 | 日韩成人在线看 | 99视频免费 | 国产一区二区 | 久久精品99国产精品日本 | 欧美日韩在线观看一区 | 国产精品视频在线播放 | 国产亚洲一区二区三区 | 毛片大全 | 久久久久av | 国产一级免费视频 | 99这里只有精品 | 久色视频在线观看 | 91在线观看视频 | 色在线免费视频 | 欧美理论| 日韩视频一区二区三区 | 精品国偷自产在线 | wwww.xxxx免费 | 三级视频久久 | 99re6在线视频 | 91在线精品一区二区 | 国产一区二区三区在线 | 久久精品91久久久久久再现 |