【Python3學習筆記】之【Python高階——多執行緒】
多執行緒
優點
- 實現執行緒可以把佔據長時間的程式中的任務放到後臺去處理。
- 使用者介面可以更加吸引人,比如使用者點選了一個按鈕去觸發某些事件的處理,可以彈出一個進度條來顯示處理進度。
- 程式執行速度更快。
- 在一些等待的任務實現如使用者輸入、檔案讀寫和網路收發資料等,執行緒就比較有用。在這種情況下我們可以釋放一些珍貴的資源如記憶體佔用等。
注意
每個獨立的執行緒有一個程式的入口、順序執行序列和程式出口。但是執行緒不能獨立執行,必須依存在應用程式中,由應用程式提供多個執行緒執行控制。
每個執行緒都有他自己的一組CPU暫存器,稱為執行緒上下文,改上下文反映了執行緒上次執行該執行緒的CPU暫存器狀態。
指令指標和堆疊指標暫存器是執行緒上下文的兩個重要暫存器,執行緒總是在程式得到上下文中執行的,這些地址都用於標誌 擁有執行緒 的 程式地址空間 的記憶體。
- 執行緒可以被搶佔(中斷)
- 在其它執行緒正在執行時,執行緒可以暫時擱置(睡眠)。這就是執行緒的退讓。
分類
執行緒可以分為:
- 核心執行緒:由作業系統核心建立和撤銷
- 使用者執行緒:不需要核心支援,在使用者程式中實現。
相關模組
執行緒中常用的模組為
- _thread
- threading
thread 模組已被廢棄。可以用threading 模組代替。所以在python中不在使用thread模組。但是為了相容性,將thread 重新命名為了“_thread”。
開始學習執行緒
python中有有兩種方式使用執行緒:函式或者類來包裝執行緒物件。
函式式(_thread模組演示)
用_thread 模組中的start_new_thread() 函式來產生新執行緒。語法如下:
_thread.start_new_thread ( function, args[, kwargs] )
引數說明
- function:執行緒函式
- args-傳遞給執行緒函式的引數(必須是tuple型別)
- kwargs:可選引數
import _thread
import time
# 為執行緒定義一個函式
def print_time(thread_name, sleep_time):
count = 0
while count < 5:
time.sleep(sleep_time)
count += 1
print('{}:{}'.format(thread_name, time.ctime(time.time())))
# 建立兩個執行緒
try:
_thread.start_new_thread(print_time, ('thread-1', 2))
_thread.start_new_thread(print_time, ('thread-2', 4))
except Exception as e:
print(e)
while 1:
pass
thread-1:Fri Oct 2 19:11:16 2020
thread-2:Fri Oct 2 19:11:18 2020
thread-1:Fri Oct 2 19:11:18 2020
thread-1:Fri Oct 2 19:11:20 2020
thread-2:Fri Oct 2 19:11:22 2020
thread-1:Fri Oct 2 19:11:22 2020
thread-1:Fri Oct 2 19:11:24 2020
thread-2:Fri Oct 2 19:11:26 2020
thread-2:Fri Oct 2 19:11:30 2020
thread-2:Fri Oct 2 19:11:34 2020
threading 模組
python 通過兩個標準庫 _thread 和 threading 提供對執行緒的支援。
_thread 提供了低階別的、原始的執行緒以及一個簡單的索,它相比於threading 模組的功能還是比較有限的。
threading 模組除了包含 _thread 模組中的 多有方法外,還提供了:
- threading.currentThread():返回當前執行緒變數。
- threading.enumerate():返回一個包含正在執行的執行緒list。正在執行指執行緒啟動後、結束前,不包括啟動前和終止後的執行緒
- threading.activeCount():返回正在執行的執行緒數量,與len(threading.enumerate())有相同的結果
除了使用方法外,執行緒模組同樣提供了Thread 類來處理執行緒,Thread 類提供了以下方法:
- run():用以表示執行緒活動的方法。
- start():啟動執行緒活動。
- join([time]):等待至執行緒中止。這阻塞呼叫執行緒直至執行緒的join() 方法被呼叫中止(正常退出、丟擲未處理異常或者可選的超時發生)
- isAlive():返回執行緒是否活動的。
- getName():返回執行緒名。
- getName():設定執行緒名。
執行緒傳遞引數方法
1.元組
threading.Thread(target=方法名,args=(引數1,引數2, ...))
import time
import threading
def song(a,b,c):
print(a, b, c)
for i in range(5):
print("song")
time.sleep(1)
if __name__ == "__main__":
threading.Thread(target=song,args=(1,2,3)).start()
2.字典
threading.Thread(target=方法名, kwargs={"引數名": 引數1, "引數名": 引數2, ...})
threading.Thread(target=song,kwargs={"a":1,"c":3,"b":2}).start() #引數順序可以變
使用threading 模組建立執行緒
可以通過threading.Thread 繼承建立一個新的子類,並例項化後呼叫start() 方法啟動新執行緒,即它呼叫了run() 方法:
import threading
import time
class MyThread(threading.Thread):
def __init__(self, thread_id, name, delay):
threading.Thread.__init__(self)
self.thread_id = thread_id
self.name = name
self.delay = delay
def run(self):
print('開始執行緒:' + self.name)
print_time(self.name, self.delay, 5)
print('退出執行緒:' + self.name)
def print_time(thread_name, delay, counter):
while counter:
time.sleep(delay)
print('{}:{}'.format(thread_name, time.ctime(time.time())))
counter -= 1
# 建立新執行緒
thread1 = MyThread(1, 'Thread-1', 1)
thread2 = MyThread(2, 'Thread-2', 2)
# 開始新執行緒
thread1.start()
thread2.start()
thread1.join()
thread2.join()
print('退出主執行緒')
開始執行緒:Thread-1
開始執行緒:Thread-2
Thread-1:Sat Oct 3 10:15:20 2020
Thread-1:Sat Oct 3 10:15:21 2020Thread-2:Sat Oct 3 10:15:21 2020
Thread-1:Sat Oct 3 10:15:22 2020
Thread-2:Sat Oct 3 10:15:23 2020Thread-1:Sat Oct 3 10:15:23 2020
Thread-1:Sat Oct 3 10:15:24 2020
退出執行緒:Thread-1
Thread-2:Sat Oct 3 10:15:25 2020
Thread-2:Sat Oct 3 10:15:27 2020
Thread-2:Sat Oct 3 10:15:29 2020
退出執行緒:Thread-2
退出主執行緒
執行緒同步
如果多個執行緒共同對某個資料進行修改,則可能出現未知結果。為了保證資料的準確性,需要對多個執行緒進行同步。
使用Thread 物件的Lock 和 Rlock 可以實現簡單的執行緒同步,這兩個物件都有acquire 方法和release 方法,對於那些需要每次只允許一個執行緒操作的資料,可以將其操作放到acquire 方法和release 方法之間。如下:
多執行緒的優勢在於可以同時執行多個任務。但是當執行緒需要共享資料時,可能存在資料不同步的問題。
考慮這樣一種情況:一個列表裡的所有元素都是0,執行緒“set”從前往後把所有元素改為1,執行緒“print”則負責從前往後列印。
那麼就有可能列印的執行緒比設定的執行緒要快,將沒有改為1的列印出來,就會出現前面列印的為1,後面列印的為0的情況。為了避免這種情況,引入了鎖的概念。
鎖有兩種狀態——鎖定和未鎖定。如執行緒1要訪問共享資料時,資料就必須先鎖定;這時執行緒2訪問時就會被阻塞,等到執行緒1訪問完畢,資料釋放鎖,執行緒2即可訪問。這樣處理後就可以得到執行緒同步的效果。(也就不會出現上面兩個執行緒同時列印成一行的結果)
import threading
import time
class MyThread(threading.Thread):
def __init__(self, thread_id, name, delay):
threading.Thread.__init__(self)
self.thread_id = thread_id
self.name = name
self.delay = delay
def run(self):
print('開始執行緒:' + self.name)
print_time(self.name, self.delay, 5)
print('退出執行緒:' + self.name)
def print_time(thread_name, delay, counter):
while counter:
time.sleep(delay)
# 鎖定狀態,不讓另一個執行緒同時列印
threadingLock.acquire()
print('{}:{}'.format(thread_name, time.ctime(time.time())))
# 釋放鎖
threadingLock.release()
counter -= 1
# 建立執行緒同步鎖例項
threadingLock = threading.Lock()
# 建立新執行緒
thread1 = MyThread(1, 'Thread-1', 1)
thread2 = MyThread(2, 'Thread-2', 2)
# 執行緒列表
threads = [thread1, thread2]
# 開始所有執行緒
for t in threads:
t.start()
# 等待執行緒結束
for t in threads:
t.join()
print('退出主執行緒')
開始執行緒:Thread-1
開始執行緒:Thread-2
Thread-1:Sat Oct 3 10:32:16 2020
Thread-1:Sat Oct 3 10:32:17 2020
Thread-2:Sat Oct 3 10:32:17 2020
Thread-1:Sat Oct 3 10:32:18 2020
Thread-2:Sat Oct 3 10:32:19 2020
Thread-1:Sat Oct 3 10:32:19 2020
Thread-1:Sat Oct 3 10:32:20 2020
退出執行緒:Thread-1
Thread-2:Sat Oct 3 10:32:21 2020
Thread-2:Sat Oct 3 10:32:23 2020
Thread-2:Sat Oct 3 10:32:25 2020
退出執行緒:Thread-2
退出主執行緒
執行緒優先順序佇列(Queue)
python 的Queue 模組中提供了同步的、執行緒安全的佇列類,包括**FIFO(先進先出)**佇列Queue,LIFO(後進先出)佇列LifoQueue,和優先順序佇列PriorityQueue。
這些佇列都實現了鎖源語,能夠線上程中直接使用,可以使用佇列來實現執行緒間的同步。
Queue 模組中的常用方法:
- Queue.qsize():返回佇列的大小。
- Queue.empty():如果佇列為空,返回True,反之False。
- Queue.full():如果佇列滿了,返回True,反之False。
- Queue.get([block[,timeout]]):獲取佇列,timeout 等待時間。
- Queue.get_nowait():相當於Queue.get(False)。
- Queue.put(item):寫入佇列,timeout等待時間。
- Queue.put_nowait(item):相當於Queue.put(item,False)
- Queue.task_done():在完成一項工作後,Queue.task_done 函式向任務已完成的佇列傳送一個訊號。
- Queue.join():實際上意味著等到佇列為空,再執行別的操作。
import queue
import threading
import time
exitFlag = 0
# 執行緒鎖例項
queueLock = threading.Lock()
# 創見一個佇列,最大容量為10
workQueue = queue.Queue(10)
# 建立執行緒子類
class MyThread(threading.Thread):
def __init__(self, thread_id, name, q):
threading.Thread.__init__(self)
self.thread_id = thread_id
self.name = name
self.q = q
def run(self):
print('開始執行緒' + self.name)
process_data(self.name, self.q)
print('結束執行緒', self.name)
def process_data(thread_name, q):
while not exitFlag:
queueLock.acquire()
# 佇列如果不為空
if not workQueue.empty():
# 列印一個佇列中的元素
data = q.get()
queueLock.release()
print('{} processing {}'.format(thread_name, data))
else:
queueLock.release()
time.sleep(1)
threadList = ['Thread-1', 'Thread-2', 'Thread-3']
nameList = ['One', 'Two', 'Three', 'Four', 'Five']
# 已經開始的執行緒列表
threads = []
threadID = 1
# 建立執行緒
for threadName in threadList:
thread = MyThread(threadID, threadName, workQueue)
thread.start()
threads.append(thread)
threadID += 1
# 填充佇列
queueLock.acquire()
# 將nameList中的元素新增到佇列
for word in nameList:
workQueue.put(word)
queueLock.release()
# 等待佇列清空
while not workQueue.empty():
pass
# 通知執行緒退出
exitFlag = 1
# 等待所有執行緒完成
for t in threads:
t.join()
print('退出程式')
開始執行緒Thread-1
開始執行緒Thread-2
開始執行緒Thread-3
Thread-2 processing One
Thread-3 processing Two
Thread-1 processing Three
Thread-2 processing Four
Thread-1 processing Five
結束執行緒 Thread-3
結束執行緒 Thread-2
結束執行緒 Thread-1
退出程式
相關文章
- Python學習筆記 - 多執行緒Python筆記執行緒
- 多執行緒學習筆記執行緒筆記
- Python學習筆記|Python之執行緒Python筆記執行緒
- JAVA學習筆記之 多執行緒賣票Java筆記執行緒
- Java 多執行緒學習筆記Java執行緒筆記
- java學習筆記--多執行緒Java筆記執行緒
- 多執行緒學習筆記 (轉)執行緒筆記
- Java學習筆記之執行緒Java筆記執行緒
- Java多執行緒學習筆記(自用)Java執行緒筆記
- C#多執行緒學習筆記C#執行緒筆記
- Java 多執行緒學習筆記(三)-守護執行緒Java執行緒筆記
- python3 多執行緒Python執行緒
- C# 多執行緒學習筆記 – 1C#執行緒筆記
- Java多執行緒學習筆記(二) (轉)Java執行緒筆記
- iOS執行緒學習筆記iOS執行緒筆記
- Java 多執行緒 學習筆記(二)停止執行緒的幾種方法Java執行緒筆記
- 多執行緒筆記執行緒筆記
- Thinking in Java---多執行緒學習筆記(2)ThinkingJava執行緒筆記
- Java 多執行緒學習筆記(四)yield 介紹Java執行緒筆記
- Java 多執行緒學習筆記(五)synchronized 鎖重入Java執行緒筆記synchronized
- JavaEE進階知識學習----多執行緒JUC高階知識-5-執行緒池-Callable-執行緒排程Java執行緒
- python 多程式和多執行緒學習Python執行緒
- Thinking in Java--Java多執行緒學習筆記(1)ThinkingJava執行緒筆記
- Java多執行緒學習筆記(六) 長樂未央篇Java執行緒筆記
- iOS 多執行緒筆記iOS執行緒筆記
- Java多執行緒筆記Java執行緒筆記
- 多執行緒筆記 一執行緒筆記
- 多執行緒筆記 三執行緒筆記
- 多執行緒筆記 二執行緒筆記
- 多執行緒學習一(多執行緒基礎)執行緒
- Linux程式執行緒學習筆記Linux執行緒筆記
- java學習筆記.04——執行緒池Java筆記執行緒
- Java 高階 --- 多執行緒快速入門Java執行緒
- python進階(9)多執行緒Python執行緒
- python執行緒筆記Python執行緒筆記
- Python學習之程式和執行緒Python執行緒
- Java多執行緒學習——執行緒通訊Java執行緒
- Java多執行緒學習(2)執行緒控制Java執行緒