并發編程
并發編程

并發:假的多任務
并行:真的多任務
多線程threading,利用cpu和i/o 可以同時執行的原理,讓CPU不在等待i/o完成
多進程multiprocessing,利用多核CPU的能力,真正的平行執行任務
異步i/o asyncio ,在單線程利用CPU和io同時執行的原理,實現函數異步執行
使用lock對資源加鎖,防止沖突訪問
使用queue實現不同線程、進程之間的數據通信,實現生產者和消費者模型
使用線程池Pool,進程池Pool。簡化線程進程的任務提交,等待結果,獲取結果。
使用subprocess啟動外部程序的進程,并進行輸入輸出交互。
CPU密集型:
是i/o在很短的時間內可以完成,CPU需要大量的計算和處理,特點是CPU的利用率相當的高
壓縮和解壓縮,加密解密,正則表達式等
i/o密集型:
是系統運作大部分的狀況是CPU在等i/o的讀寫操作,CPU的利用率低
文件處理程序,網絡爬蟲程序,讀寫數據庫程序
多線程Thread
優點:相比進程,更加輕量級,占用資源少
缺點:相對進程,多線程只能并發執行,不能利用多cpu(GIL)
相比協程,啟動數目有限,占用資源,有線程切換開銷
適用于:i/o密集型計算,同時運行的任務數目要求不多
多線程數據通信的queue.Queue
queue.Queue可以用于多線程之間的,線程安全的數據通信
1. 引入類庫
import queue
2,創建Queue
q = queue.Queue()
3.添加元素
q.put(item)
4.獲取元素
item = q.get()
5.查詢狀態
q.qsize() #用來判斷元素的多少
q.empty() #用來判斷是否為空
q.full() # 判斷是否已滿
lock 用于解決線程安全問題
用法一:try——finally模式
import threading
lock = threading.Lock()
lock.acquire()
try:
#do something
finally:
lock.release()
用法二:with模式
import threading
lock = threading.Lock()
with lock:
#do something
線程池
優點:
1. 提升性能:因為減去了大量新建,終止線程的開銷,重用了線程的資源:
2. 適用場景:事和處理突發性大量請求或者需要大量線程完成任務,但實際任務處理時間較短
3. 防御功能:有效避免系統因為創建線程過多,而導致的負荷過大相應變慢的問題
4. 代碼優勢:使用線程池的語法比自己興建線程執行更加簡潔
線程的生命周期

ThreadPoolExecutor的使用語法
方式一:map函數,很簡單
注意:map的結果和入參是順序對應的
from concurrent.future import ThreadPoolExecutor,as_completad
with ThreadPoolExecutor() as pool:
results = pool.map(craw,urls) #urls 為參數列表
for result in results:
print(result)
方式二:future模式,更強大
注意:如果使用as_completed順序是不定的
from concurrent.future import ThreadPoolExecutor,as_completad
with ThreadPoolExecutor() as pool:
futures = [pool。submit(crawl,url for url in urls]
for future in futures: # 有序返回
print(future.result())
for future in as_completed(futures): # 無序返回
print(future.result())
使用線程池改造程序
多進程process
優點:可以利用多核CPU并行運算
缺點:占用資源最多,可啟用的數目比線程少
適用于:CPU密集型計算
注意點:


多協程Corutine
優點:內存開銷最少,啟動的線程數目多
缺點:支持的庫有限(aiohttp vs requests)代碼實現復雜
適用于:i/o密集型計算,需要超多任務運行,但有現成庫支持的場景
GIL(全局解釋器鎖)
是計算機編程語言解釋器用于同步線程的一種機制,它使得任何時可僅有一個行程在執行,即使在多核心處理器上,使用GIL的解釋器也只允許同一時間執行一個線程。(保證引用計數器的安全)
Python 異步i/o庫介紹:asyncio
注意:
要用在異步i/o編程中
依賴的庫必須支持異步i/o特性
爬蟲引用中:
requests 不支持異步,需要用aiohttp
import asyncio
#獲取事件循環
loop = asyncio.get_event_lppp()
#定義協程
saync def myfunc():
await get_url(url)
# 創建task列表
tasks = [loop.create_task(myfunc(url) for url in urls]
# 執行爬蟲事件列表
loop.run_until_complete(asyncio.wait(tasks))
信號量(英語:Semaphore)
信號量,又稱為信號量。旗語是一個同步對象,用于保持在0到指定最大值之間的一個數值
1. 當線程完成一次對該semaphore對象的等待(wait)時,該計數值減一。
2. 當線程完成一次對semaphore對象的釋放(release)時,計數值加一。
3. 當計數值為0 ,測線程等待該semaphore對象不再能成功直到該semaphore對象變成signaled狀態
4. semaphore對象的計數值大于0 ,為signaled狀態,計數值等于0,為nonsignaled狀態。
使用方法一:
sem = asynciko。Semaphore(10)
@ ...later
async with sem:
# work with shared resource
使用方法二:
sem = asyncio.Semaphore(10)
# ....later
await sam.acquire()
try:
# work with shared resource
finally:
sem.release()
使用subprocess啟動電腦的子進程
subptoces 模塊:
允許你生成新的進程
連接它們的輸入,輸出,錯誤管道
并且獲取它們的返回值
應用場景
每天定時8:00自動打開酷狗音樂播放歌曲
調用7z。exe自動解壓縮.7z文件
通過Python遠程提交一個torrent種子文件,用電腦啟動下載

浙公網安備 33010602011771號