python3-多線程


多線程簡介
線程(Thread)也稱輕量級進程,時操作系統能夠進行運算調度的最小單位,它被包涵在進程之中,時進程中的實際運作單位。線程自身不擁有資源,只擁有一些在運行中必不可少的資源,但他可與同屬一個進程的其他線程共享進程所擁有的全部資源。一個線程可以創建和撤銷另一個線程,同一進程中的多個線程之間可以並發執行。
線程有就緒/阻塞/運行三種基本狀態:
  1/ 就緒狀態是指線程具備運行的所有條件,邏輯上可以運行,在等待處理機
  2 / 運行狀態是指線程占有處理機正在運行。
  3/ 阻塞狀態是指線程在等待一個事件(如某個信號量),邏輯上不可執行

結論:在python中,對於計算密集型任務,多進程占優勢;對於I/O密集型任務,多線程占優勢

python多線程其它介紹

1/1 多線程threading模塊
方法一 創建threading.Thread類的實例,調用其start()方法
方法二 繼承Thread類,在子類中重寫run()和init()方法


1/2 多線程同步Lock(互訴鎖)
#如果多個線程共同對某個數據修改,則可能出現不可預料的結果,這個時候就需要使用互訴鎖來進行同步
#調用鎖
lock = threading.Lock()
#獲取鎖,用戶線程同步
lock.acquire()

1/3 多線程同步Semaphore(信號量)
互訴鎖是只允許一個線程訪問共享數據,而信號量是同時允許一定數量的線程訪問共享數據
semaphore = threading.BoundedSemaphore()

練習:
import threading
import time

semaphore = threading.BoundedSemaphore(5)

def yewubanli(name):
semaphore.acquire()
time.sleep(3)
print(f"{time.strftime('%Y-%m-%d %H:%M:%S')} {name} 正在辦理業務")

semaphore.release()


thread_list = []
for i in range(12):
t = threading.Thread(target=yewubanli, args=(i,))
thread_list.append(t)

for thread in thread_list:
thread.start()

for thread in thread_list:
thread.join()

1/4 多線程同步Condition
條件對象Condition能讓一個線程A停下來,等待其它線程B,線程B滿足了某個條件后通知(notify)線程A繼續運行。線程首先獲取一個條件變量鎖,如果條件不足,則該線程等待(wait)並釋放條件變量鎖;如果條件滿足,就繼續執行線程,執行完成后可以通知(notify)其它狀態為wait的線程執行。其它處於wait狀態的線程接到通知后會重新判斷條件以確定是否繼續執行。
cond = threading.Condition()

1/5 多線程同步Event
事件用於線程之間的通信。一個線程發出一個信號,其它一個或多個線程等待,調用Event對象的wait方法,線程則會阻塞等待,直到別的線程set之后才會被喚醒
cond = threading.Event()


1/6 線程優先級隊列(queue)
Python的queue模塊中提供了同步的/線程安全的隊列類,包括先進先出隊列Queue/后進后出隊列LifoQueue和優先級隊列PriorityQueue。這些隊列都實現了鎖原語,可以直接使用來實現線程之間的同步。

練習:
import threading, time
import queue


q = queue.Queue(maxsize=5)

def ProducerA():
count = 1
while True:
q.put(f"冷飲 {count}")
print(f"{time.strftime('%H:%M:%S')} A 放入:[冷飲 {count}]")
count += 1
time.sleep(1)

def ConsumerB():
while True:
print(f"{time.strftime('%H:%M:%S')} B 取出 [{q.get()}]")
time.sleep(5)

p = threading.Thread(target=ProducerA)
c = threading.Thread(target=ConsumerB)

c.start()
p.start()


1/7 多線程之線程池pool
在面向對象編程中,創建和銷毀對象是很費時間的,因為創建一個對象要獲取內存資源或其它更多資源。虛擬機也將視圖跟蹤每一個對象,以便能夠在對象銷毀后進行垃圾回收。同樣的道理,多任務情況下每次都會生成一個新線程,執行任務后資源再被回收就顯得非常低效,因此線程池就是解決這個問題的方法。類似的還有連接池/進程池等。
將任務添加到線程池中,線程池會自動指定一個空閑的線程取執行任務,當超過線程池的最大線程數時,任務需要等待有新的空閑線程后才會被執行。
我們可以使用threading模塊及queue模塊定制線程池,也可以使用multiprocessing。from multiprocessing import Pool這樣導入的Pool表示的時進程池,from multiprocessing.dummy import Pool這樣導入的Pool表示的時線程池

練習:
from multiprocessing.dummy import Pool as ThreadPool
import time


def fun(n):
time.sleep(2)

start = time.time()
for i in range(5):
fun(i)
print("單線程順序執行耗時:", time.time() - start)

start2 = time.time()

pool = ThreadPool(processes=5)
results2 = pool.map(fun, range(5))
pool.close()
pool.join()
print("線程池(5)並發執行耗時:",time.time() - start2)


總結:
Python多線程適合用再I/O密集型任務中。I/O密集型任務較小時間用再CPU計算上,較多時間用再I/O上,如文件讀寫/web請求/數據庫請求等;而對於計算密集型任務,應該使用多進程


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM