Python 標準庫之 threading (線程並行)

示例

返回活躍線程的數量

In [1]: import threading

In [2]: threading.active_count()
Out[2]: 22
    
In [3]: len(threading.enumerate())
Out[3]: 22

返回活躍線程列表

In [1]: import threading

In [2]: threading.enumerate()
Out[2:
[<_MainThread(MainThread, started 3744)>,
 <HistorySavingThread(IPythonHistorySavingThread, started 9356)>,
 <Thread(ThreadPoolExecutor-0_0, started daemon 6552)>,
 <Thread(ThreadPoolExecutor-0_1, started daemon 9492)>,
 <Thread(ThreadPoolExecutor-0_2, started daemon 8740)>,
 <Thread(ThreadPoolExecutor-0_3, started daemon 4128)>,
 <Thread(ThreadPoolExecutor-0_4, started daemon 288)>,
 <Thread(ThreadPoolExecutor-0_5, started daemon 2804)>,
 <Thread(ThreadPoolExecutor-0_6, started daemon 5848)>,
 <Thread(ThreadPoolExecutor-0_7, started daemon 9608)>,
 <Thread(ThreadPoolExecutor-0_8, started daemon 6348)>,
 <Thread(ThreadPoolExecutor-0_9, started daemon 7156)>,
 <Thread(ThreadPoolExecutor-0_10, started daemon 4268)>,
 <Thread(ThreadPoolExecutor-0_11, started daemon 7364)>,
 <Thread(ThreadPoolExecutor-0_12, started daemon 7532)>,
 <Thread(ThreadPoolExecutor-0_13, started daemon 5888)>,
 <Thread(ThreadPoolExecutor-0_14, started daemon 364)>,
 <Thread(ThreadPoolExecutor-0_15, started daemon 5816)>,
 <Thread(ThreadPoolExecutor-0_16, started daemon 9636)>,
 <Thread(ThreadPoolExecutor-0_17, started daemon 6756)>,
 <Thread(ThreadPoolExecutor-0_18, started daemon 10080)>,
 <Thread(ThreadPoolExecutor-0_19, started daemon 7264)>]

創建一個線程

In [1]: import threading

In [2]: thread = threading.Thread()

In [3]: thread
Out[3]: <Thread(Thread-1, initial)>

爲線程綁定任務

In [1]: import threading

In [2]: thread = threading.Thread()
    
In [3]: def f1():
   ...:     print("Her")
   ...:

In [4]: thread.target = f1

In [5]: thread.target
Out[5]: <function __main__.f1()>

In [1]: import threading

In [2]: def f1():
   ...:     print("Her")
   ...:

In [2]: thread = threading.Thread(target=f1)

爲線程任務傳遞參數

In [1]: import threading

In [2]: def f1(i):
   ...:     print("Her"+str(i))
   ...:

In [2]: thread = threading.Thread(target=f1, args=(666,))

運行線程

In [1]: import threading

In [2]: def f1(i):
   ...:     print("Her"+str(i))
   ...:

In [2]: thread = threading.Thread(target=f1, args=(666,))

In [3]: thread.start()
Her666

注意:

In [1]: thread.run()
Her666
  • start() 方法是啓動一個子線程
  • run() 方法並不啓動一個新線程,而是在主線程中調用了任務函數。
  • start() 它在一個線程裏最多隻能被調用一次。

阻塞調用的線程 (守護線程)

不使用 join()

import threading
import time

def f1():
    for i in range(2):
        print("thread1", time.ctime())
        time.sleep(1) 
        
thread1 = threading.Thread(target=f1)
thread1.start()
print("done")

輸出:

thread1 Wed Mar 18 18:52:23 2020
done
thread1 Wed Mar 18 18:52:24 2020

使用 join()

import threading
import time

def f1():
    for i in range(2):
        print("thread1", time.ctime())
        time.sleep(1) 
        
thread1 = threading.Thread(target=f1)
thread1.start()
thread1.join()
print("done")

輸出:

thread1Wed Mar 18 18:55:55 2020
thread1Wed Mar 18 18:55:56 2020
done

使用 join() 會將調用這個線程的主線程阻塞,等待當前線程終止後纔將控制權交還給主線程。

多線程訪問臨界值

import threading
import time

a = 0

def f1():
    
    global a
    t = a + 1
    print(t)
    time.sleep(1) # 模擬修改變量值的時間過程
    a = t
 
threads = [threading.Thread(target=f1) for _ in range(5)] 
for _ in threads:
    _.start()

輸出:

1
1
1
1
1

CPU 太快了,導致 time.sleep(1) 休眠沒有結束就跑完所有線程,此時線程獲取到 a 的值都是 0

線程鎖

# 創建線程鎖
lock = threading.Lock()
# 獲得鎖
lock.acquire() 
# 釋放鎖
lock.release() 

爲臨界資源加鎖:

import threading
import time

lock = threading.Lock()
a = 0

def f1():
    
    global a
    lock.acquire() 
    t = a + 1
    print(t)
    time.sleep(1) # 模擬修改變量值的時間過程
    a = t
    lock.release()
 
threads = [threading.Thread(target=f1) for _ in range(5)] 
for _ in threads:
    _.start()

輸出:

1
2
3
4
5

參考

threading.active_count() : 返回當前活躍的線程對象的數量
threading.current_thread() : 返回當前線程對象
threading.excepthook(args, /) : 處理 Thread.run() 未捕獲的異常
threading.get_ident() : 返回當前線程的索
threading.get_native_id() : 返回內核分配給當前線程的原生集成線程 ID
threading.enumerate() : 以列表形式返回當前所有存活的 Thread 對象
threading.main_thread() : 返回主 Thread 對象
threading.settrace(func) : 爲所有 threading 模塊開始的線程設置追蹤函數
threading.setprofile(func) : 爲所有 threading 模塊開始的線程設置性能測試函數
threading.stack_size([size]) : 返回創建線程時用的堆棧大小
threading.TIMEOUT_MAX : 阻塞函數( Lock.acquire(), RLock.acquire(), Condition.wait(), …)中形參 timeout 允許的最大值

threading.local() :創建本地線程數據

線程對象

threading.Thread(group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None) : 創建線程對象

參數 說明
group group 應該爲 None;爲了日後擴展 ThreadGroup 類實現而保留
target 用於 run()方法調用的可調用對象
name 線程名稱
args 調用目標函數的參數元組
kwargs 用目標函數的關鍵字參數字典
daemon 是否爲守護模式,默認值 None 爲線程將繼承當前線程的守護模式屬性

start() :開始線程活動。
run() :代表線程活動的方法。 標準的 run() 方法會對作爲 target 參數傳遞給該對象構造器的可調用對象(如果存在)發起調用,並附帶從 argskwargs 參數分別獲取的位置和關鍵字參數
join(timeout=None) : 等待,直到線程終結。
name :只用於識別的字符串。
getName()setName() :獲取/設置 name 的值。
ident :這個線程的 ‘線程標識符’
native_id :該線程的當前線程ID。
is_alive() :返回線程是否存活。
daemon :一個表示這個線程是(True)否(False)守護線程的布爾值。
isDaemon()setDaemon() :獲取/設置 name的值。

鎖對象

threading.Lock() :創建所。
acquire(blocking=True, timeout=-1) :可以阻塞或非阻塞地獲得鎖。
release() :釋放一個鎖。
locked() :如果獲得了鎖則返回真值。

更多參考

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章