Python併發程式設計教程 從效能角度初探併發程式設計

2021-09-09 06:05:32 字數 4302 閱讀 5892

作為高階系列的乙個分支「併發程式設計」,我覺得這是每個程式設計師都應該會的。

併發程式設計這個系列,我準備了將近乙個星期,從知識點梳理,到思考要舉哪些例子才能更加讓人容易吃透這些知識點。希望呈現出來的效果真能如想象中的那樣,對小白也一樣的友好。

課程大綱

對於併發程式設計,python 的實現,總結了一下,大致有如下三種方法:

在之後的章節裡,將陸陸續續地給大家介紹到這三個知識點。

在開始講解理論知識之前,先過一下幾個基本概念。雖然咱是高階教程,但我也希望寫得更小白,更通俗易懂。

序列:乙個人在同一時間段只能幹一件事,譬如吃完飯才能看電視;

並行:乙個人在同一時間段可以幹多件事,譬如可以邊吃飯邊看電視;

在python中,多執行緒協程雖然是嚴格上來說是序列,但卻比一般的序列程式執行效率高得很。

一般的序列程式,在程式阻塞的時候,只能幹等著,不能去做其他事。就好像,電視上播完正劇,進入廣告時間,我們卻不能去趁廣告時間是吃個飯。對於程式來說,這樣做顯然是效率極低的,是不合理的。

當然,學完這個課程後,我們就懂得,利用廣告時間去做其他事,靈活安排時間。這也是我們多執行緒協程要幫我們要完成的事情,內部合理排程任務,使得程式效率最大化。

雖然多執行緒協程已經相當智慧型了。但還是不夠高效,最高效的應該是一心多用,邊看電視邊吃飯邊聊天。這就是我們的多程序才能做的事了。

為了更幫助大家更加直觀的理解,在網上找到兩張圖,來生動形象的解釋了多執行緒和多程序的區別。(侵刪)

文字總是蒼白無力的,千言萬語不如幾行**來得孔武有力。

首先,我的實驗環境配置如下

注意

以下**,若要理解,對小白有如下知識點要求:

裝飾器的運用

多執行緒的基本使用

多程序的基本使用

當然,看不懂也沒關係,主要最後的結論,能讓大家對單執行緒、多執行緒、多程序在實現效果上有個大體清晰的認識,達到這個效果,本文的使命也就完成了,等到最後,學完整個系列,不妨再回頭來理解也許會有更深刻的理解。

下面我們來看看,單執行緒,多執行緒和多程序,在執行中究竟孰強孰弱。

開始對比之前,首先定義四種型別的場景

為什麼是這幾種場景,這和多執行緒多程序的適用場景有關。結論裡,我再說明。

# cpu計算密集型

def count(x=1, y=1):

# 使程式完成150萬計算

c = 0

while c 

c += 1

x += x

y += y

# 磁碟讀寫io密集型

def io_disk():

with open("file.txt", "w") as f:

for x in range(5000000):

f.write("python-learning\n")

# 網路io密集型

header = 

# 【模擬】io密集型

def io_simulation():

time.sleep(2)

比拼的指標,我們用時間來考量。時間耗費得越少,說明效率越高。

為了方便,使得**看起來,更加簡潔,我這裡先定義是乙個簡單的時間計時器的裝飾器。

如果你對裝飾器還不是很了解,也沒關係,你只要知道它是用於 計算函式執行時間的東西就可以了。

def timer(mode):

def deco(*args, **kw):

type = kw.setdefault('type', none)

t1=time.time()

func(*args, **kw)

t2=time.time()

cost_time = t2-t1

return deco

第一步,先來看看單執行緒的

@timer("【單執行緒】")

def single_thread(func, type=""):

for i in range(10):

func()

# 單執行緒

single_thread(count, type="cpu計算密集型")

single_thread(io_disk, type="磁碟io密集型")

single_thread(io_request,type="網路io密集型")

single_thread(io_simulation,type="模擬io密集型")

看看結果

第二步,再來看看多執行緒的

@timer("【多執行緒】")

def multi_thread(func, type=""):

thread_list = 

for i in range(10):

t=thread(target=func, args=())

t.start()

e = len(thread_list)

while true:

for th in thread_list:

if not th.is_alive():

e -= 1

if e <= 0:

break

# 多執行緒

multi_thread(count, type="cpu計算密集型")

multi_thread(io_disk, type="磁碟io密集型")

multi_thread(io_request, type="網路io密集型")

multi_thread(io_simulation, type="模擬io密集型")

看看結果

第三步,最後來看看多程序

@timer("【多程序】")

def multi_process(func, type=""):

process_list = 

for x in range(10):

p = process(target=func, args=())

p.start()

e = process_list.__len__()

while true:

for pr in process_list:

if not pr.is_alive():

e -= 1

if e <= 0:

break

# 多程序

multi_process(count, type="cpu計算密集型")

multi_process(io_disk, type="磁碟io密集型")

multi_process(io_request, type="網路io密集型")

multi_process(io_simulation, type="模擬io密集型")

看看結果

將結果彙總一下,製成**。

我們來分析下這個**。

首先是cpu密集型,多執行緒以對比單執行緒,不僅沒有優勢,顯然還由於要不斷的加鎖釋放gil全域性鎖,切換執行緒而耗費大量時間,效率低下,而多程序,由於是多個cpu同時進行計算工作,相當於十個人做乙個人的作業,顯然效率是成倍增長的。

然後是io密集型,io密集型可以是磁碟io網路io資料庫io等,都屬於同一類,計算量很小,主要是io等待時間的浪費。通過觀察,可以發現,我們磁碟io,網路io的資料,多執行緒對比單執行緒也沒體現出很大的優勢來。這是由於我們程式的的io任務不夠繁重,所以優勢不夠明顯。

所以我還加了乙個「模擬io密集型」,用sleep來模擬io等待時間,就是為了體現出多執行緒的優勢,也能讓大家更加直觀的理解多執行緒的工作過程。單執行緒需要每個執行緒都要sleep(2),10個執行緒就是20s,而多執行緒,在sleep(2)的時候,會切換到其他執行緒,使得10個執行緒同時sleep(2),最終10個執行緒也就只有2s.

可以得出以下幾點結論

Java併發程式設計教程

1 使用執行緒的經驗 設定名稱 響應中斷 使用threadlocal 2 executor executorservice和future 3 阻塞佇列 put和take offer和poll drainto 4 執行緒間的協調手段 lock condition wait notify notifya...

Java併發程式設計教程

多執行緒程式包含兩個或多個可同時執行的部分,每個部分可以同時處理不同的任務,從而能更好地利用可用資源,特別是當您的計算機有多個cpu時。多執行緒使您能夠寫入多個活動,可以在同一程式中同時進行操作處理。新執行緒 new 新執行緒在新的狀態下開始其生命週期。直到程式啟動執行緒為止,它保持在這種狀態。它也...

Go Context 併發程式設計教程

waitgroup 和通道 channel 是常見的 2 種併發控制的方式。如果併發啟動了多個子協程,需要等待所有的子協程完成任務,waitgroup 非常適合於這類場景,例如下面的例子 123 4567 891011 1213 1415 16var wg sync.waitgroup func d...