python 并發(fā)與并行
并發(fā)和并行都用于多線程程序,但是它們之間的相似性和差異存在很多混淆。這方面的一個重要問題是:并發(fā)并行性與否?盡管這兩個術(shù)語看起來非常相似,但上述問題的答案是否定的,但并發(fā)性和并行性并不相同?,F(xiàn)在,如果它們不相同,那么它們之間的基本區(qū)別是什么?
簡單來說,并發(fā)性涉及管理來自不同線程的共享狀態(tài)訪問,另一方面,并??行性涉及利用多個cpu或其核心來提高硬件性能。
并發(fā)細節(jié)
并發(fā)是指兩個任務(wù)在執(zhí)行時重疊??赡苁菓贸绦蛲瑫r在多個任務(wù)上進行的情況。我們可以用圖解理解它; 多項任務(wù)正在同時取得進展,具體如下 -
并發(fā)級別
在本節(jié)中,我們將從編程方面討論三個重要的并發(fā)級別 -
低級并發(fā)
在這種并發(fā)級別中,明確使用原子操作。我們不能在應用程序構(gòu)建中使用這種并發(fā)性,因為它非常容易出錯且難以調(diào)試。甚至python也不支持這種并發(fā)。
中級并發(fā)
在這種并發(fā)中,沒有使用顯式原子操作。它使用顯式鎖。python和其他編程語言支持這種并發(fā)。大多數(shù)應用程序員使用這種并發(fā)性。
高級并發(fā)
在這種并發(fā)中,既不使用顯式原子操作也不使用顯式鎖。python有 concurrent.futures 模塊來支持這種并發(fā)。
并發(fā)系統(tǒng)的屬性
要使程序或并發(fā)系統(tǒng)正確,必須滿足某些屬性。與終止系統(tǒng)有關(guān)的屬性如下 -
正確的財產(chǎn)
正確性屬性意味著程序或系統(tǒng)必須提供所需的正確答案。為了簡單起見,我們可以說系統(tǒng)必須正確地將起始程序狀態(tài)映射到最終狀態(tài)。
安全財產(chǎn)
安全屬性意味著程序或系統(tǒng)必須保持 “良好” 或 “安全” 狀態(tài),并且永遠不會做任何 “壞事” 。
生活財產(chǎn)
此屬性意味著程序或系統(tǒng)必須 “取得進展” 并且它將達到某種理想狀態(tài)。
并發(fā)系統(tǒng)的參與者
這是并發(fā)系統(tǒng)的一個常見屬性,其中可以有多個進程和線程,它們同時運行以在自己的任務(wù)上取得進展。這些進程和線程稱為并發(fā)系統(tǒng)的actor。
并發(fā)系統(tǒng)的資源
演員必須利用內(nèi)存,磁盤,打印機等資源才能執(zhí)行任務(wù)。
某些規(guī)則
每個并發(fā)系統(tǒng)必須擁有一套規(guī)則來定義演員要執(zhí)行的任務(wù)類型以及每個系統(tǒng)的時間安排。任務(wù)可能是獲取鎖,內(nèi)存共享,修改狀態(tài)等。
并發(fā)系統(tǒng)的障礙
在實現(xiàn)并發(fā)系統(tǒng)時,程序員必須考慮以下兩個重要問題,這些問題可能是并發(fā)系統(tǒng)的障礙 -
共享數(shù)據(jù)
實現(xiàn)并發(fā)系統(tǒng)時的一個重要問題是在多個線程或進程之間共享數(shù)據(jù)。實際上,程序員必須確保鎖保護共享數(shù)據(jù),以便對其進行所有訪問,并且一次只有一個線程或進程可以訪問共享數(shù)據(jù)。如果多個線程或進程都試圖訪問相同的共享數(shù)據(jù),那么除了其中至少一個之外的所有線程或進程都不會被阻止并且將保持空閑狀態(tài)。換句話說,我們可以說當鎖定生效時我們只能使用一個進程或線程。可以有一些簡單的解決方案來消除上述障礙
數(shù)據(jù)共享限制
最簡單的解決方案是不共享任何可變數(shù)據(jù)。在這種情況下,我們不需要使用顯式鎖定,并且可以解決由于相互數(shù)據(jù)導致的并發(fā)障礙。
數(shù)據(jù)結(jié)構(gòu)協(xié)助
很多時候并發(fā)進程需要同時訪問相同的數(shù)據(jù)。除了使用顯式鎖之外,另一種解決方案是使用支持并發(fā)訪問的數(shù)據(jù)結(jié)構(gòu)。例如,我們可以使用 隊列 模塊,它提供線程安全的隊列。我們還可以使用 multiprocessing.joinablequeue 類來實現(xiàn)基于多處理的并發(fā)。
不可變數(shù)據(jù)傳輸
有時,我們使用的數(shù)據(jù)結(jié)構(gòu),比如并發(fā)隊列,不適合我們可以傳遞不可變數(shù)據(jù)而不鎖定它。
可變數(shù)據(jù)傳輸
繼續(xù)上述解決方案,假設(shè)是否只需要傳遞可變數(shù)據(jù)而不是不可變數(shù)據(jù),那么我們就可以傳遞只讀的可變數(shù)據(jù)。
共享i / o資源
實現(xiàn)并發(fā)系統(tǒng)的另一個重要問題是線程或進程使用i / o資源。當一個線程或進程使用i / o這么長時間而其他線程或進程空閑時,就會出現(xiàn)問題。在處理i / o繁重的應用程序時,我們可以看到這種障礙。在示例的幫助下可以理解從web瀏覽器請求頁面。這是一個繁重的應用程序。在這里,如果請求數(shù)據(jù)的速率低于它的消耗速率,那么我們的并發(fā)系統(tǒng)中就有i / o障礙。
以下python腳本用于請求網(wǎng)頁并獲取我們的網(wǎng)絡(luò)獲取所請求頁面所花費的時間
import urllib.request import time ts = time.time() req = urllib.request.urlopen('http://www.codingdict.com') pagehtml = req.read() te = time.time() print("page fetching time : {} seconds".format (te-ts))
執(zhí)行上述腳本后,我們可以獲取頁面獲取時間,如下所示。
產(chǎn)量
page fetching time: 1.0991398811340332 seconds
我們可以看到獲取頁面的時間超過一秒?,F(xiàn)在,如果我們想要獲取數(shù)千個不同的網(wǎng)頁,您可以了解我們的網(wǎng)絡(luò)將花費多少時間。
什么是parallelism?
并行性可以定義為將任務(wù)分成可以同時處理的子任務(wù)的技術(shù)。如上所述,它與并發(fā)性相反,其中兩個或多個事件同時發(fā)生。我們可以用圖解理解它; 任務(wù)分為若干可以并行處理的子任務(wù),如下所示 -
要更多地了解并發(fā)性和并行性之間的區(qū)別,請考慮以下幾點 -
并發(fā)但不平行
應用程序可以是并發(fā)但不是并行意味著它同時處理多個任務(wù),但任務(wù)不會分解為子任務(wù)。
并行但不并發(fā)
應用程序可以是并行但不是并發(fā)意味著它一次只能在一個任務(wù)上運行,并且可以并行處理分解為子任務(wù)的任務(wù)。
無論是并行還是并發(fā)
應用程序既不能并行也不能并發(fā)。這意味著它一次只能處理一個任務(wù),并且任務(wù)永遠不會分解為子任務(wù)。
并行和并發(fā)
應用程序可以是并行和并發(fā)意味著它既可以一次處理多個任務(wù),也可以將任務(wù)分解為子任務(wù)以并行執(zhí)行它們。
并行性的必要性
我們可以通過在單個cpu的不同核心之間或在網(wǎng)絡(luò)內(nèi)連接的多個計算機之間分配子任務(wù)來實現(xiàn)并行性。
考慮以下要點,以了解為什么有必要實現(xiàn)并行性 -
高效的代碼執(zhí)行
借助并行性,我們可以有效地運行代碼。它將節(jié)省我們的時間,因為部分中的相同代碼并行運行。
比順序計算更快
順序計算受物理和實際因素的限制,因此不可能獲得更快的計算結(jié)果。另一方面,這個問題通過并行計算解決,并且比順序計算給我們更快的計算結(jié)果。
減少執(zhí)行時間
并行處理減少了程序代碼的執(zhí)行時間。
如果我們談?wù)摬⑿行缘恼鎸嵗?,我們計算機的顯卡就是突出并行處理真正力量的例子,因為它擁有數(shù)百個獨立工作的獨立處理內(nèi)核,可以同時執(zhí)行。由于這個原因,我們也能夠運行高端應用程序和游戲。
了解處理器的實現(xiàn)
我們知道并發(fā)性,并行性和它們之間的區(qū)別,但是它實現(xiàn)的系統(tǒng)又如何呢?理解我們將要實施的系統(tǒng)是非常必要的,因為它為我們提供了在設(shè)計軟件時做出明智決策的好處。我們有以下兩種處理器
單核處理器
單核處理器能夠在任何給定時間執(zhí)行一個線程。這些處理器使用 上下文切換 在特定時間存儲線程的所有必要信息,然后再恢復信息。上下文切換機制可以幫助我們在給定秒內(nèi)的多個線程上取得進展,看起來好像系統(tǒng)正在處理多個事情。
單核處理器具有許多優(yōu)點。這些處理器需要更少的功率,并且多個核之間沒有復雜的通信協(xié)議。另一方面,單核處理器的速度有限,不適合大型應用。
多核處理器
多核處理器具有多個獨立的處理單元,也稱為 核心 。
這樣的處理器不需要上下文切換機制,因為每個核包含執(zhí)行一系列存儲指令所需的一切。
獲取 - 解碼 - 執(zhí)行周期
多核處理器的核心遵循一個執(zhí)行周期。該循環(huán)稱為 fetch-decode-execute 循環(huán)。它涉及以下步驟 -
取
這是循環(huán)的第一步,它涉及從程序存儲器中取出指令。
解碼
最近獲取的指令將被轉(zhuǎn)換為一系列信號,這些信號將觸發(fā)cpu的其他部分。
執(zhí)行
這是執(zhí)行讀取和解碼指令的最后一步。執(zhí)行結(jié)果將存儲在cpu寄存器中。
這里的一個優(yōu)點是多核處理器中的執(zhí)行速度比單核處理器的執(zhí)行速度快。它適用于大型應用。另一方面,多核之間的復雜通信協(xié)議是一個問題。多核需要比單核處理器更多的功率。