鍍金池/ 教程/ Python/ 并發(fā)vs并行
事件驅動程序
反應式編程
進程池
線程
線程池
Python并發(fā)簡介
并發(fā)vs并行
同步線程
調試線程應用程序
進程間通信
線程通信
Python并發(fā)編程教程
測試線程應用程序
基準和性能分析
系統(tǒng)和內(nèi)存架構
線程的實現(xiàn)
多進程

并發(fā)vs并行

并發(fā)性和并行性都用于多線程程序,但它們之間的相似性和差異存在很多混淆。 在這方面的一個大問題是:并發(fā)是不是就是并行? 雖然這兩個術語看起來很相似,但對上述問題的答案是否定的,并發(fā)性和并行性并不相同。 現(xiàn)在,如果它們不一樣,它們之間的基本區(qū)別是什么?

簡而言之,并發(fā)處理的是處理來自不同線程的共享狀態(tài)訪問,而并行處理利用多個CPU或其內(nèi)核來提高硬件性能。

并發(fā)簡介

并發(fā)是兩個任務在執(zhí)行過程中重疊的時候。 這可能是一個應用程序正在同時處理多個任務的情況。 我們可以用圖解理解它; 多項任務正在同時取得進展,如下所示 -

并發(fā)級別

在本節(jié)中,我們將討論編程方面的三個重要級別的并發(fā)性 -

1. 低級并發(fā)
在這種并發(fā)級別中,顯式使用了原子操作。 我們不能在構建應用程序時使用這種并發(fā)性,因為它非常容易出錯并且很難調試。 即使Python不支持這種并發(fā)性。

2. 中級并發(fā)
在這種并發(fā)中,沒有使用顯式的原子操作。 它使用顯式鎖。 Python和其他編程語言支持這種并發(fā)性。 大多數(shù)應用程序員使用這種并發(fā)性。

3. 高級并發(fā)
在這種并發(fā)中,不使用顯式原子操作也不使用顯式鎖。 Python有concurrent.futures模塊來支持這種并發(fā)。

并發(fā)系統(tǒng)的性質

要使程序或并發(fā)系統(tǒng)正確,一些屬性必須由它來滿足。 與終止系統(tǒng)相關的屬性如下 -

正確性屬性
正確性屬性意味著程序或系統(tǒng)必須提供所需的正確答案。 為了簡單起見,可以說系統(tǒng)必須正確地將啟動程序狀態(tài)映射到最終狀態(tài)。

安全屬性
安全屬性意味著程序或系統(tǒng)必須保持“良好”或“安全”狀態(tài),并且從不做任何“壞”的事情。

活躍度屬性
這個屬性意味著一個程序或系統(tǒng)必須“取得進展”,并且會達到一個理想的狀態(tài)。

并發(fā)系統(tǒng)的行為者
這是并發(fā)系統(tǒng)的一個常見屬性,其中可以有多個進程和線程,它們同時運行以在他們自己的任務上取得進展。 這些進程和線程稱為并發(fā)系統(tǒng)的角色。

并發(fā)系統(tǒng)的資源
行為者必須利用內(nèi)存,磁盤,打印機等資源來執(zhí)行任務。

某些規(guī)則集
每個并發(fā)系統(tǒng)必須擁有一套規(guī)則來定義執(zhí)行者要執(zhí)行的任務類型和每個任務的執(zhí)行時間。 任務可能是獲取鎖,共享內(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ù)結構協(xié)助
很多時候并發(fā)進程需要同時訪問相同的數(shù)據(jù)。 與使用顯式鎖相比,另一種解決方案是使用支持并發(fā)訪問的數(shù)據(jù)結構。 例如,可以使用提供線程安全隊列的隊列模塊。 也可以使用multiprocessing.JoinableQueue類來實現(xiàn)基于多處理的并發(fā)。

不可變的數(shù)據(jù)傳輸
有時,我們使用的數(shù)據(jù)結構(比如說并發(fā)隊列)不適合,那么可以傳遞不可變數(shù)據(jù)而不鎖定它。

可變數(shù)據(jù)傳輸
繼續(xù)上面的解決方案,假設如果它只需要傳遞可變數(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)絡用于獲取請求頁面的時間 -

import urllib.request
import time
ts = time.time()
req = urllib.request.urlopen('http://www.yiibai.com')
pageHtml = req.read()
te = time.time()
print("Page Fetching Time : {} Seconds".format (te-ts))

執(zhí)行上述腳本后,可以獲取頁面獲取時間,如下所示。

Page Fetching Time: 0.999139881798332 Seconds

可以看到,獲取該頁面的時間差不多是一秒鐘。 現(xiàn)在,如果我們想要訪問數(shù)千個不同的網(wǎng)頁,您可以大概知道訪問網(wǎng)絡需要多少時間。

什么是并行性?

并行可定義為將任務分解為可同時處理的子任務的技術。 如上所述,它與并發(fā)性相反,其中兩個或更多事件同時發(fā)生。 我們可以用圖解理解它; 一個任務被分解成可以并行處理的多個子任務,如下所示 -

并行但不平行
應用程序可以是并行的,但不是并行的,意味著它可以同時處理多個任務,但任務不會分解為子任務。

并行但不并發(fā)
一個應用程序可以是并行的,但不是并行的,意味著它一次只能在一個任務上工作,并且分解為子任務的任務可以并行處理。

既不平行也不并發(fā)
應用程序既不能并行也不能并發(fā)。 這意味著它一次只能處理一項任務,并且任務不會被分解為子任務。

并行和并發(fā)
應用程序既可以是并行的,也可以是并行的,這意味著它既可以同時在多個任務上工作,也可以將任務分解為子任務并行執(zhí)行。

并行的必要性

我們可以通過在單CPU的不同內(nèi)核之間或網(wǎng)絡內(nèi)連接的多臺計算機之間分配子任務來實現(xiàn)并行。

考慮以下要點來理解為什么有必要實現(xiàn)并行性 -

有效的代碼執(zhí)行
借助并行性,我們可以高效地運行代碼。 它將節(jié)省時間,因為部分中的相同代碼并行運行。

比順序計算更快速
順序計算受到物理和實際因素的限制,因此無法獲得更快的計算結果。 另一方面,這個問題可以通過并行計算來解決,并且比順序計算提供更快的計算結果。

執(zhí)行時間更短
并行處理減少了程序代碼的執(zhí)行時間。

如果要談論真實生活中并行性的例子,我們計算機的圖形卡就是一個例子,它強調了并行處理的真正能力,因為它擁有數(shù)百個獨立工作的獨立處理內(nèi)核,并且可以同時執(zhí)行。 由于這個原因,我們也能夠運行高端應用程序和游戲。

理解處理器的實現(xiàn)

我們知道并發(fā)性,并行性以及它們之間的差異,但是它將如何實現(xiàn)。 理解將要實施的系統(tǒng)是非常必要的,因為它使我們在設計軟件時能夠做出明智的決定。有以下兩種處理器 -

單核處理器
單核處理器能夠在任何給定時間執(zhí)行一個線程。 這些處理器使用上下文切換來在特定時間存儲線程的所有必要信息,然后再恢復信息。 上下文切換機制有助于我們在給定秒內(nèi)的多個線程上取得進展,并且看起來好像系統(tǒng)正在處理多種事情。

單核處理器具有許多優(yōu)點。 這些處理器需要更少的功率,并且多個內(nèi)核之間沒有復雜的通信協(xié)議。 另一方面,單核處理器的速度有限,不適合更大的應用。

多核處理器
多核處理器具有多個獨立處理單元,也稱為核心。

這種處理器不需要上下文切換機制,因為每個核心都包含執(zhí)行一系列存儲指令所需的所有內(nèi)容。

讀取 - 解碼 - 執(zhí)行的周期

多核處理器的內(nèi)核遵循一個執(zhí)行周期。 這個周期被稱為讀取 - 解碼 - 執(zhí)行周期。 它涉及以下步驟 -

讀取
這是循環(huán)的第一步,它涉及從程序存儲器讀取指令。

解碼
最近讀取的指令將被轉換為一系列觸發(fā)CPU其他部分的信號。

執(zhí)行
這是獲取和解碼指令將被執(zhí)行的最后一步。 執(zhí)行結果將存儲在CPU寄存器中。

這里的一個優(yōu)勢是多核處理器的執(zhí)行速度比單核處理器的執(zhí)行速度快。 它適用于更大的應用程序。 另一方面,多核之間的復雜通信協(xié)議是一個問題。 多核需要比單核處理器需要更多的功率。