您現在的位置是:首頁 > 舞蹈首頁舞蹈

「併發操作」協程,執行緒,程序是什麼,在python中怎麼應用?

由 嘉為科技 發表于 舞蹈2021-09-05
簡介celery即為訊息中介軟體,任務執行單元,任務執行結果儲存的形式進行非同步操作,如圖:總結請看如下例子: 有一個老闆想要開個工廠進行生產剪子,他需要花一些財力物力製作一條生產線,這個生產線上有很多的器件以及材料這些所有的,為了能夠生產剪子

協程和執行緒有什麼差別,優勢呢?

「併發操作」協程,執行緒,程序是什麼,在python中怎麼應用?

生活中的多工時時刻刻存在,例如小張一邊碼字一邊看螢幕,又例如小蔡可以一邊跳舞一邊打籃球,這就是生活中的多工。那麼計算機中的多工是什麼呢、怎麼使用呢?就讓我們一起探討計算機中,多工-執行緒、多工-程序、多工-協程的理解以及在python中的應用。

多工

多工處理是指使用者可以在同一時間內進行多種操作,每個操作被稱作一個任務。在計算機中,同時開啟迅雷以及QQ是多工同時進行,在迅雷中看電影的時候,進行邊下邊播也是多工,在同一時間同一單位進行的不同操作,都可以理解為多工。

現在多核CPU已經非常普及了,但事實上,過去即便是單核CPU也可以執行多工。由於CPU執行程式碼都是順序執行的,那單核CPU是怎麼執行多工的呢?

答案就是作業系統輪流讓各個任務交替執行,任務1執行0。01秒,切換到任務2,任務2執行0。01秒,再切換到任務3,……這樣反覆執行下去。表面上看,每個任務都是交替執行的,但是,由於CPU的執行速度實在是太快了,我們感覺就像所有任務都在同時執行。

真正實現並行執行多工只能在多核CPU上實現,但往往任務數量遠遠多於CPU的核心數量,所以作業系統也會自動把很多工輪流排程到每個核心上執行。在這裡我們引入

併發

並行

以及

佇列

的概念:

併發:

cpu透過在任務間快速切換達到多工

一起

執行,但實際上並不是同時執行,舉例:

A和B去跑步,跑道很擠只能容納一個人,兩人約定好每人跑一秒,大家都跑一秒就退出跑道。這時,在同一時間內,總有一個人在跑道內、一個人在跑道外(下圖中兩隊人排同一個咖啡機即為併發)

並行:

每個任務都有不同cpu去執行,達到多工一起執行,實際是真正的同時執行,舉例還是A和B兩人去跑步。這次跑道升級了,有兩條跑道,A和B實現了並肩奔跑,你我互不影響(圖中兩隊人排兩臺咖啡機即為並行)

佇列:

就是一個有序的排列,在多工中需要把待執行的任務排好隊,有序執行。在A和B跑步的例子中,假設有20個A和20個B需要跑步,在排隊等待跑步的時候,形成的排列就稱為佇列(圖中兩個隊伍即為佇列)

「併發操作」協程,執行緒,程序是什麼,在python中怎麼應用?

併發並行與佇列

思考:迅雷播放電影的同時用QQ聊天,和在迅雷中看電影邊下邊播多工有什麼不同?

1、執行緒

一個程式執行起來至少有一個程序,一個程序至少有一個執行緒;

處理器cpu分配給執行緒,即cpu真正執行的是執行緒中的程式碼;

分配cpu給執行緒時,是透過時間片輪訓方式進行的;

程序是作業系統分配程式執行資源的單位,而執行緒是程序的一個實體;

是CPU排程和分配的單位。

在上述思考中,迅雷和QQ屬於不同的程序,迅雷下載電影和播放電影屬於不同的執行緒,即一開始分配了兩份資源給迅雷和QQ,迅雷和QQ各為一個程序。

當你開啟迅雷邊下邊播功能的時候,在迅雷這個程序中又新開了兩個執行緒,不斷地在下載和播放間進行切換,達到多工的效果。 執行緒與程序是屬於關係。

執行緒由程序建立,程序結束執行緒也結束了,但執行緒結束程序不一定結束,cpu最終分配給的是執行緒,而不是程序。

執行緒執行程式碼片段原理:執行緒獲得cpu執行記憶體,執行當前程式碼,在執行另一個程式碼塊之前打上時間戳,儲存上下文然後去執行另一程式碼塊。當再次回到該程式碼塊時載入時間戳,上下文,驗證執行的合理性,如此反覆執行下去,在不同的需要執行的程式碼塊間切換。

「併發操作」協程,執行緒,程序是什麼,在python中怎麼應用?

程序與執行緒間的關係

子執行緒何時開啟,何時執行?

當呼叫thread。start()時 開啟執行緒,再執行執行緒的程式碼。

子執行緒何時結束?

子執行緒把target指向的函式中的語句執行完畢後,或者執行緒中的run函式程式碼執行完畢後,立即結束當前子執行緒。

檢視當前執行緒數量

透過threading。enumerate()可列舉當前執行的所有執行緒。

主執行緒何時結束?

所有子執行緒執行完畢後,主執行緒才結束。

2、程序

程序:

一個程式執行起來後,程式碼+用到的資源 稱之為程序,它是作業系統分配資源的基本單位。

程序狀態:

工作中,任務數往往大於cpu的核數,即一定有一些任務正在執行,而另外一些任務在等待cpu進行執行,因此導致了有了不同的狀態。

「併發操作」協程,執行緒,程序是什麼,在python中怎麼應用?

就緒態:

執行的條件都已經滿足,正在等在cpu執行。

執行態:

cpu正在執行其功能。

等待態:

等待某些條件滿足,例如一個程式sleep了,此時就處於等待態,好比說:紅綠燈、等待訊息回覆、等待同步鎖都是處於等待態。

3、協程

協程是python中另外一種實現多工的方式,只不過比執行緒更小佔用、執行單元,由於協程是本世紀出現的新概念,所以對於協程來說沒有統一的概念,這裡介紹我自己的理解,

協程相當於更便捷更輕量的執行緒

協程與執行緒差異在於,實現多工時, 執行緒切換從系統層面遠不止儲存和恢復 CPU上下文這麼簡單。作業系統為了程式執行的高效性,每個執行緒都有自己快取Cache等資料,作業系統還會幫你做這些資料的恢復操作。所以執行緒的切換非常耗效能。但是協程的切換隻是單純操作CPU的上下文,所以一秒鐘切換個上百萬次系統都扛得住。

4、佇列與他們的關係

三者在工作時都需要取得cpu,為了避免彼此之間爭奪cpu,所以需要對他們進行排隊處理,排好的隊伍就叫佇列,例如執行緒池、程序池。

「併發操作」協程,執行緒,程序是什麼,在python中怎麼應用?

佇列的原理

5、三者間的關係

程序>執行緒>協程

執行緒由程序建立,屬於程序,協程是程序更小程度的劃分,更輕便靈活,如下圖:

「併發操作」協程,執行緒,程序是什麼,在python中怎麼應用?

程序執行緒協程三者間的關係

在python中實現多工

1、Python實現多執行緒

「併發操作」協程,執行緒,程序是什麼,在python中怎麼應用?

自定義類,繼承threading。Thread;

建立物件;

呼叫物件的run()方法。

2、Python實現多程序

「併發操作」協程,執行緒,程序是什麼,在python中怎麼應用?

例項化一個物件 target= 指定到對應的函式;

呼叫物件的run()方法。

3、Python實現多協程

「併發操作」協程,執行緒,程序是什麼,在python中怎麼應用?

函式中呼叫yield;

呼叫yield後函式會在執行到呼叫send() 方法結果返回時才繼續進行下一步;

執行函式,函式會交替執行。

多工的痛點及解決方法

1、痛點1

如果多個執行緒同時對同一個全域性變數操作,會出現資源競爭問題,從而資料結果會不正確。

「併發操作」協程,執行緒,程序是什麼,在python中怎麼應用?

執行上述程式碼後會發現兩個執行緒對同一個資料操作完後得到的資料不一樣,這就是遇到了執行緒安全問題。

解決方法:

同步就是協同步調,按預定的先後次序執行。如:你說完,我再說;你做完,我再做;你執行完,我再執行。

在多執行緒程式設計中,一些敏感資料不允許被多個執行緒同時訪問,因為會出現執行緒安全問題。透過執行緒同步機制,能保證共享資料在任何時刻,最多有一個執行緒訪問,以保證資料的正確性。執行緒同步提示的幾點:

執行緒同步就是執行緒排隊;

共享資源的讀寫才需要同步;

變數才需要同步,常量不需要同步;

給資料加鎖,即我操作完你再操作,你操作完我再操作。

threading模組中定義了Lock類,可以方便的處理鎖定:

「併發操作」協程,執行緒,程序是什麼,在python中怎麼應用?

「併發操作」協程,執行緒,程序是什麼,在python中怎麼應用?

「併發操作」協程,執行緒,程序是什麼,在python中怎麼應用?

2、痛點2

GIL全域性直譯器鎖:顧名思義,這是直譯器內部的一把鎖,確切一點說是CPython直譯器內部的一把鎖,所以要注意區分我們在Python程式碼中使用的Lock不是一個層面的概念。言外之意,就是全域性直譯器就是為了鎖定整個直譯器內部的全域性資源,每個執行緒想要執行首先獲取GIL,而GIL本身又是一把互斥鎖,造成所有執行緒只能一個一個one-by-one-併發-交替的執行。

也就是說python中多執行緒並不能很好的實現併發操作,但python恰好又是實現多協程的一種方法,所以對於python來說,實現多工最好的方式即為

多程序+多協程

擴充套件 celery原理

celery是基於python實現的一個非同步任務的排程工具,同時還是一個任務佇列,主要用於處理耗時的任務。

大家在使用celery的時候,都需要去配置一個佇列才能繼續使用,因為對於celery來說,也是一個生產者消費者的模式,我們一般是用的佇列是Redis或者RabbitMQ,因為儲存格式為鍵值對形式,序號對應任務,利於cpu執行。celery即為訊息中介軟體,任務執行單元,任務執行結果儲存的形式進行非同步操作,如圖:

「併發操作」協程,執行緒,程序是什麼,在python中怎麼應用?

總結

請看如下例子: 有一個老闆想要開個工廠進行生產剪子,他需要花一些財力物力製作一條生產線,這個生產線上有很多的器件以及材料這些所有的,為了能夠生產剪子而準備的資源稱之為:

程序

只有生產線是不能夠進行生產的,所以老闆的找個工人來進行生產,這個工人能夠利用這些材料最終一步步的將剪子做出來,這個來做事情的工人稱之為:

執行緒

這個老闆為了提高生產率,想到3種辦法:

在這條生產線上多招些工人,一起來做剪子,這樣效率是成倍増長,即單程序 多執行緒方式。

老闆發現這條生產線上的工人不是越多越好,因為一條生產線的資源以及材料畢竟有限,所以老闆又花了些財力物力購置了另外一條生產線,然後再招些工人這樣效率又再一步提高了,即多程序 多執行緒方式。

老闆發現,現在已經有了很多條生產線,並且每條生產線上已經有很多工人了(即程式是多程序的,每個程序中又有多個執行緒),為了再次提高效率,老闆想了個損招,規定:如果某個員工在上班時臨時沒事或者再等待某些條件(比如等待另一個工人生產完某道工序 之後他才能再次工作) ,那麼這個員工就利用這個時間去做其它的事情,那麼也就是說:如果一個執行緒等待某些條件,可以充分利用這個時間去做其它事情,其實這就是:協程方式。

簡單來說:

程序是作業系統資源分配的單位;

執行緒是CPU排程的單位;

程序切換需要的資源最大,效率很低;

執行緒切換需要的資源一般,效率一般(當然在不考慮GIL的情況下);

協程切換任務資源很小,效率高;

多程序、多執行緒根據cpu核數不一樣可能是並行的,但是協程是在一個執行緒中所以是併發。

其他優質文章

恭喜!藍鯨DevOps平臺助力中國人保財險透過DevOps持續交付3級!

「愛嬰島」千店千面多元母嬰零售,雲化系統支援業務發展!

持續整合頻繁的程式碼檢查怎麼辦,瞭解下自動化的靜態程式碼檢查!

「深度分析」關於SPN不正確導致SQL資料庫連線失敗

「知識科普」安全測試OWASP ZAP簡介