讓我們首先了解計算機體系結構中線程的概念。
在計算中,進程是正在執行的計算機程序的實例。任何過程都有 3 個基本組件:
線程是進程中可以安排執行的實體。此外,它是可以在操作系統(操作系統)中執行的最小處理單元。
簡單來說,線程是程序中可以獨立於其他代碼執行的此類指令序列。為簡單起見,您可以假設線程只是進程的子集!
線程在線程控制塊 (TCB) 中包含所有這些信息:
請參考下圖以了解進程與其線程之間的關系:
一個進程中可以存在多個線程,其中:
請參考下圖以了解內存中如何存在多個線程:
在Python中,線程模塊提供了一個非常簡單直觀的API,用於在程序中生成多個線程。
讓我們考慮一個使用線程模塊的簡單示例:
import threading
def print_cube(num):
"""用於打印給定數字的多維數據集的函數"""
print("Cube: {}".format(num * num * num))
def print_square(num):
"""函數打印給定數值的平方"""
print("Square: {}".format(num * num))
if __name__ == "__main__":
# 創建線程
t1 = threading.Thread(target=print_square, args=(10,))
t2 = threading.Thread(target=print_cube, args=(10,))
# 啟動線程1
t1.start()
# 啟動線程2
t2.start()
# 等待線程1完全執行
t1.join()
# 等待線程2完全執行
t2.join()
# 兩個線程都已完全執行
print("Done!")
運行結果:
讓我們試著理解上面的代碼:
要導入線程模塊,我們需要:
import threading
要創建一個新線程,我們創建一個 Thread 類的對象。它需要以下參數:
在上面的例子中,我們創建了2個具有不同目標函數的線程:
t1 = threading.Thread(target=print_square, args=(10,))
t2 = threading.Thread(target=print_cube, args=(10,))
要啟動線程,我們使用 Thread 類的 start 方法。
t1.start()
t2.start()
一旦線程啟動,當前程序(你可以把它想象成一個主線程)也會繼續執行。為了停止當前程序的執行,直到線程完成,我們使用連接方法。
t1.join()
t2.join()
因此,當前程序將首先等待 t1 的完成,然後等待 t2 完成。完成後,將執行當前程序的其餘語句。
考慮下圖,以更好地了解上述程序的工作原理:
考慮下面給出的python程序,其中我們為每個任務打印線程名稱和相應的進程:
import threading
import os
def task1():
print("任務1分配給線程: {}".format(threading.current_thread().name))
print("運行任務1的進程ID: {}".format(os.getpid()))
def task2():
print("任務2分配給線程: {}".format(threading.current_thread().name))
print("運行任務2的進程ID: {}".format(os.getpid()))
if __name__ == "__main__":
# 打印當前進程的ID
print("運行主程序的進程ID: {}".format(os.getpid()))
# 打印主線程名稱
print("主線程名稱: {}".format(threading.current_thread().name))
# 創建線程
t1 = threading.Thread(target=task1, name='t1')
t2 = threading.Thread(target=task2, name='t2')
# 啟動線程
t1.start()
t2.start()
# 等待所有線程完成
t1.join()
t2.join()
運行結果:
讓我們試著理解上面的代碼:
我們使用 os.getpid() 函數來獲取當前進程的 ID。
print("運行主程序的進程ID: {}".format(os.getpid()))
從輸出中可以清楚地看出,所有線程的進程 ID 都保持不變。
我們使用threading.main_thread() 函數來獲取主線程對象。在正常情況下,主線程是啟動Python解釋器的線程。線程對象的 name 屬性用於獲取線程的名稱。
print("主線程名稱: {}".format(threading.main_thread().name))
我們使用 threading.current_thread() 函數來獲取當前線程對象。
print("任務1分配的線程: {}".format(threading.current_thread().name))
下圖闡明了上述概念: