Python - 中斷線程

大家好,有志於成為 Python 程式設計師的你!今天,我們將深入探討一個令人興奮的主題:在 Python 中中斷線程。如果你是程式設計的新手,也別擔心;我會一步步引導你完成這段旅程,就像過去多年教學中,我對無數學生所做的那樣。讓我們一起展開這次冒險吧!

Python - Interrupting a Thread

線程是什麼?

在我們跳進中斷線程的主題之前,先快速回顧一下線程是什麼。想像你正在讀一本書(主程序),突然想起你需要打電話。你標記了你的頁面(創建一個線程),打了電話,然後回到你的書上。這就是線程在程式設計中的工作方式——它們允許程序同時進行多項工作。

線程中斷

現在,假設你正在打電話,但電話打得有點久,你想回到你的書上。你如何禮貌地結束通話?這就是線程中斷的用處。在 Python 中,我們有幾種方法可以做到這一點:

  1. 使用事件對象
  2. 使用旗標

讓我們透過一些有趣的例子來探索這兩種方法!

使用事件對象中斷線程

事件對象就像一個可以設定或清除的旗標。當旗標被設定時,它會向線程發出停止的信號。

以下是一個簡單的例子:

import threading
import time

def worker(event):
while not event.is_set():
print("工作中...")
time.sleep(1)
print("工作線程:我完成了!")

# 創建一個事件對象
stop_event = threading.Event()

# 創建並啟動線程
thread = threading.Thread(target=worker, args=(stop_event,))
thread.start()

# 讓線程運行 5 秒鐘
time.sleep(5)

# 設定事件以信號線程停止
stop_event.set()

# 等待線程完成
thread.join()

print("主程序:全部完成!")

讓我們來解析一下:

  1. 我們導入了必要的模組:threading 用於處理線程,time 用於添加延時。
  2. 我們定義了一個 worker 函數,該函數在事件被設定之前會一直工作。
  3. 我們創建了一個名為 stop_eventEvent 對象。
  4. 我們創建並啟動一個線程,將 stop_event 傳遞給它。
  5. 我們使用 time.sleep(5) 讓線程運行 5 秒鐘。
  6. 我們使用 stop_event.set() 設定事件,這會向線程發出停止的信號。
  7. 我們使用 thread.join() 等待線程完成。

當你運行這個程序時,你會看到 "工作中..." 被打印出來好幾次,然後是 "工作線程:我完成了!",接著是 "主程序:全部完成!"。

使用旗標中斷線程

中斷線程的另一種方法是使用簡單的布林旗標。這種方法比較手動,但非常有效。

以下是一個例子:

import threading
import time

def counting_sheep(stop_flag):
count = 0
while not stop_flag[0]:
count += 1
print(f"數羊:{count}")
time.sleep(1)
print(f"我數了 {count} 棵羊才睡著!")

# 創建一個可變對象來保存我們的旗標
stop_flag = [False]

# 創建並啟動線程
thread = threading.Thread(target=counting_sheep, args=(stop_flag,))
thread.start()

# 讓線程數羊數 5 秒鐘
time.sleep(5)

# 將旗標設為 True 以停止線程
stop_flag[0] = True

# 等待線程完成
thread.join()

print("主程序:甜蜜的夢鄉!")

讓我們分析一下這段代碼:

  1. 我們定義了一個 counting_sheep 函數,該函數會計數直到 stop_flag 被設為 True 為止。
  2. 我們創建了一個包含單個布林元素的列表 stop_flag。我們使用列表是因為它是可變的,允許我們從線程外部修改它。
  3. 我們創建並啟動一個線程,將 stop_flag 傳遞給它。
  4. 我們讓線程數羊數 5 秒鐘。
  5. 我們將 stop_flag[0] 設為 True,向線程發出停止的信號。
  6. 我們使用 thread.join() 等待線程完成。

當你運行這個程序時,你會看到羊的數量增加大約 5 秒鐘,然後是最後的計數,接著是 "主程序:甜蜜的夢鄉!"。

方法比較

讓我們比較這兩種方法:

方法 优點 缺點
事件對象 - 內建同步
- 清晰且符合 Python 風格
- 需要傳遞事件對象
旗標 - 簡單易於實現
- 不需要額外的對象
- 手動同步
- 可能出現競態條件

結論

恭喜你!你剛剛學會了兩種在 Python 中中斷線程的方法。事件對象方法通常因其內建同步而受到青睞,但旗標方法在更簡單的情境中也可能非常有用。

記住,就像禮貌地結束電話一樣,給你的線程機會清理一下再停止是很重要的。在現實世界的應用中,你可能需要在你的線程函數中添加一些清理代碼,這些代碼在收到停止信號時會運行。

程式設計就是實踐,所以我要鼓勵你實驗這些例子。試著修改它們,也許是添加多個線程或更改時間。誰知道呢?你或許能創造出一個有趣的 "中斷數羊遊戲"!

快樂編程,願你的線程總是能夠協調合作!

Credits: Image by storyset