深刻理解:線程,進程,協程和並行,併發-協程

爬蟲的併發控制:python

多進程、多線程、協程 yield程序員


從硬件:redis

雙核四線程(超線程技術):
有兩個CPU核心,每一個核心有兩個邏輯處理器,至關於有四個CPU核心數據庫


四核四線程:
有一個CPU核心,每一個核心有一個邏輯處理器,至關於有四個CPU核心設計模式


從操做系統:緩存

進程和線程,都是CPU任務的執行單位。安全


進程:早期的操做系統是面向進程的:
表示一個程序的執行活動(打開、執行、保存、關閉)網絡


線程:如今的操做系統都是面向線程:
表示一個進程處理任務時最小調度單位(執行功能a、執行功能b)多線程


一個程序至少開啓一個進程,一個進程至少有一個線程。併發

 

每一個進程都有獨立的內存空間,不一樣進程之間不共享任何狀態。
進程之間的通訊須要通過操做系統調度控制,通信效率低、切換開銷大。


同一個進程裏的多個線程,是共享內存空間,切換開銷小,通信效率高。
線程的工做機制是"搶佔式",出現競爭的狀態,競爭意味着數據不安全。
引入了"互斥鎖":讓多個線程安全有序的訪問內存空間的機制。

 

Python的多線程:
相似於 GIL(全局解釋器鎖):保證一個時間片裏只有一個線程在運行。
好處:直接杜絕了多個線程的競爭問題:
壞處:Python的多線程不是真正的多線程。

Python解釋器在處理IO阻塞類型的方法時,會釋放GIL
若是沒有IO操做,該線程會每隔 sys.getcheckinterval() 次釋放GIL,讓其餘線程嘗試執行。

 


並行:
同一CPU時間片內,CPU能夠同時處理多個程序。若是有多個程序,同步執行。

程序1:----------------
程序2:----------------
程序3:----------------
程序4:----------------

 

併發:
同一CPU時間片,只能處理一個程序。若是有多個程序,交替執行。

程序1: ----- ------
程序2: -----
程序3: ----
程序4: -----


多進程:能夠充分利用多核CPU的資源,適用於密集CPU任務(大量的並行運算)
Python的多進程模塊:multiprocessing

進程之間通訊成本高切換開銷大,不適用於須要大量數據通訊和切換的任務(爬蟲)

設計模式:生產者消費者(並行模式)

 

多線程:適用於密集I/O任務(磁盤IO,內存IO,網絡IO),切換開銷小通訊成本低。
Python的多線程:Thread、thraeding、multiprocessing.dummy

多線程:同一個時間片只能執行一個線程,沒法充分利用CPU多核資源(只能作到併發,不能作到並行)

 

協程:操做系統和CPU不認識協程,是由程序員經過代碼邏輯控制。
特色是在單線程下執行多個任務,且不須要經過操做系統切換(沒有切換開銷,也不須要處理鎖),執行效率高。

Python: gevent ,猴子補丁(Python代碼在執行網絡IO阻塞時,會自動切換協程)

協程:適用於密集網絡I/O任務

 

多進程爬蟲:不合適

多線程爬蟲:缺點 - 經過操做系統調度,有線程切換開銷(海量URLs場景會增長CPU負載);優勢 - 使用場景普遍(網絡讀寫併發/數據庫讀寫併發/磁盤讀寫併發)
協程爬蟲:缺點 - gevent配合monkey.patch_all() 只能提升網絡併發效率,不能處理其餘併發場景;優勢 - 經過程序員代碼邏輯控制,不受操做系統調度,沒有切換開銷,下降CPU負載(處理海量URLs優點明顯)

 


執行方式:
同步:執行一個任務,必須等待上一個任務完成(沒有併發的爬蟲)
異步:執行一個任務,沒必要等待上一個任務完成(併發的爬蟲)

程序狀態:
阻塞:程序執行時,必須等待該任務完成,不然保持等待狀態。
非阻塞:程序執行時,沒必要等待該任務完成,能夠繼續執行下一個任務。

異步+非阻塞(效率最高):
發送請求後,沒必要等待響應返回,能夠繼續處理其餘請求發送;當處理功能掛起時,可以馬上切換其餘到功能繼續執行。



異步網絡框架 Twisted Tornada

Scrapy :請求處理模塊+響應解析模塊+twisted
scrapy-redis:Scrapy + Redis(在同一個數據庫裏處理請求去重、請求分配、數據存儲)

單機爬蟲:
分佈式爬蟲:

 

CPU -> 寄存器 -> CPU緩存L1/L2/L3 -> 內存 -> 硬盤/固態硬盤 -> 網絡

 

協程:切換

三種方式實現:  1. yield   2.greenlet   3. gevent

1.yield

做用:

掛起當前函數 將後面表達式的值 返回到調用生成器的地方
接收數據 並喚醒當前函數 而且緊接着上次運行的地址繼續執行

2.greenler

greenlet(函數)  建立協程

gr2.switch()切換到gr2執行

 

 

協程是python箇中另一種實現多任務的方式,只不過比線程更小佔用更小執行單元(理解爲須要的資源)

通俗的理解:在一個線程中的某個函數,能夠在任何地方保存當前函數的一些臨時變量等信息,而後切換到另一個函數中執行,注意不是經過調用函數的方式作到的,而且切換的次數以及何時再切換到原來的函數都由開發者本身肯定

  建立並執行協程

  阻塞等待協程運行完成 .join()

  阻塞等待全部協程退出 .join_all()

  monkey.patch_all()做用是將rece, recefrom, time.sleep, accept進行破解, 不會阻塞等待, 在調用時能夠切換到別的任務繼續執行.

  注意:join,join_all做用保持主進程存活

 

簡單總結

  • 進程是資源分配的單位
  • 線程是操做系統調度的單位
  • 進程切換須要的資源很最大,效率很低
  • 線程切換須要的資源通常,效率通常
  • 協程切換任務資源很小,效率高
  • 多進程、多線程根據cpu核數不同多是並行的 也多是併發的。協程的本質就是使用當前進程在不一樣的函數代碼中切換執行,能夠理解爲並行。 協程是一個用戶層面的概念,不一樣協程的模型實現多是單線程 也多是多線程。
相關文章
相關標籤/搜索