爬蟲
第五天
多線程
線程的創建和運行
import multiprocessing
def task(num):
pass
p1 = multiprocessing.Process(target = task)
p1.start()
守護線程
一般情況下,主線程代碼執行完畢後不會結束,會等待所有子線程任務結束後才結束
如果將子線程設置爲守護線程,意味着:主線程代碼執行完畢,主線程和子線程一起立即結束
t.setDaemom(True)
多線程的隊列
from queue import Queue
q = Queue()
q.put() # 數據放入隊列,隊列計數+1
q.get() # 從隊列中取出數據,隊列計數不變
q.task_done() # 和q.gert()配合使用,隊列計數-1
q.join() # 阻塞住線程
多進程
進程的創建和運行
import multiprocessing
def task(num):
pass
p1 = multiprocessing
p1.start()
守護進程
將子進程設置爲守護進程後,主進程代碼執行完畢,主進程和子進程一起結束
p1.deamon=True
多進程的隊列
from multiprocessing import JoinableQueue as Queue
線程池
使用線程池多好處
- 降低資源消耗.通過重複利用已經創建的線程降低線程創建和銷燬造成多消耗
- 提高響應速度.當任務到達時,任務可以直接執行,而不需要等待新線程的創建
- 提高線程的可管理性.線程時稀缺資源,如果無限制的創建,不僅會消耗系統資源,還會降低系統的穩定性
- 使用線程池可以進行統一的分配,調優和監控
線程池的用法
from multiprocessing.dummy import Pool
def task():
pass
pool = Pool(5) # 線程池中子線程的最大數量,當前爲5
pool.apply_async(func=task,args=(,)) # 發佈任務,交給線程池的子線程去執行,只是發佈
pool.close() # 關閉線程池,不在接收信多任務,不是銷燬線程池
pool.join() # 阻塞主線程,等待子線程中所有的任務結束
線程池的回調:
當不清楚線程池需要做的任務數量時,可以使用線程池的回調
def _callback(temp):
print("---之前的線程任務執行完畢---")
pool.apply_async(func=task,callback=_callback) # 發佈任務,交給線程池的子線程去執行,只是發佈,當子線程執行完畢時,會自動調用callback
協程池
import gevent.monkey
gevent.monkey.patch_all()
# 協程池
from gevent.pool import Pool
from queue import Queue
# 協程池pool沒有close的方法
GIL鎖
全局解釋器鎖(GIL)是cpython解釋器中的,限制了多線程,導致統一時刻只有一個線程被調用,而且不能充分發揮CPU多核的特性
GIL的步驟
- 切換到一個線程
- 設置GIL鎖
- 執行指定字節數量的代碼
- 代碼執行完畢
- 遇到延遲操作 「time.sleep(), socket.accept(), socket.connect()」等
- 釋放GIL鎖
- 切換到其他線程繼續執行
併發和並行
- 有多核心,每個核心執行一個任務,任務數量 <= 核心數,此時並行
- 任務數量 >= 核心數此時併發