阻塞與非阻塞執行 同步與異步調用 順序與並序
兩個pool進程池的兩種調用函數:
名稱 | 英文 | 中文 | 進程執行方式 | 備註 |
---|---|---|---|---|
pool.apply() | synchronous | 同步調用 | 阻塞執行(blocking) | 效率低 |
pool.apply_aync() | asynchronous | 異步調用 | 進程是非阻塞執行(non-blocking) | 效率高 |
概念容易混雜,我們通過我自編自導的一個實例來說明
阻塞與非阻塞執行
同步與異步調用
順序與並序
異步調用 非阻塞執行 並行
理髮店(進程池 pool)有兩個理髮師1,2(被調用的進程),來了兩個顧客Mr.A,Mr.B,給客人理髮就是理髮師的任務 (函數需要計算的事項 任務),
理髮店老闆 (也就是調用子進程的父進程 調用理髮師的老闆),居高臨下的審視着一切。
老闆,都喜歡高效做事,打算用 異步調用 asynchronous 的方法 apply_aync()
,
然後進程(理髮師)是非阻塞執行的
也就是:
老闆 先調用一個理髮師(比如CPU選擇理髮師1)先去給一位顧客(比如Mr.A)理髮,不管Mr.A是否理完髮(進程是否執行完成),馬上繼續安排另一個理髮師給另一個顧客理髮,依次把所有理髮師都安排上,直到,理髮師人手用完了(進程池的進程數滿了),只能讓客戶等着(任務暫時掛起 等待)
當然了,作爲員工,肯定需要反饋老闆的安排,回一句“Yes Sir”,所以要意思意思,那是怎麼個意思,那就是這個意思(函數返回一下,但是,任務並沒有完成,應該說剛剛開始做任務)。
對被調用的進程而言(理髮師 打工的),他們工作是非阻塞的non-blocking ,我第二個理髮師接單,不會被第一個理髮師阻礙,阻塞。
對於操着上帝視角的我們, 看着可憐的理髮師1,2(被調用的兩個進程),就知道他們是**並行工作(parallel)**的。
Q1:我們代碼寫着理髮師1和Mr.A 在最前面,是不是第一個處理的一定是1呢?
A1:不是,CPU先處理調度哪個是不確定的 所以是1先還是2先,都不可控制,也無所謂(異步嘛,不影響別人)
對老闆而言,一方面他要調用員工,一方面要獲取員工的工作狀態,調用員工以後不等員工工作的結果直接安排其他員工做事,就是異步調用。那麼如果安排一個員工,並一直眼巴巴等待員工執行完成的結果,就是同步調用。
同步調用 阻塞執行 串行
異步調用說了,那麼,同步調用會怎麼樣呢?
同樣,理髮店還是有兩個理髮師1,2(被調用的進程),來了兩個顧客Mr.A Mr.B,
理髮店老闆 ,打算用 同步調用 synchronous 的方法 apply()
因爲理髮店只有一個理髮的位置QAQ
老闆 先調用一個理髮師(比如CPU選擇理髮師1)先去給一位顧客(比如Mr.A)理髮,然後焦急的等待理髮師1 爲 Mr.A 理完髮(進程是否執行完成),才能繼續安排另一個理髮師給另一個顧客理髮,
終於 理髮師1理完了,理髮師給老闆說一聲(函數返回),另一位理髮師(比如理髮師2)才能上去。注意沒有函數回調了,只有返回。
對被調用的進程而言(理髮師 打工的),他們工作是阻塞的, 我第二個人接單會被第一個理髮師阻塞。
對於操着上帝視角的我們, 看着可憐的理髮師1,2(被調用的兩個進程),就知道他們是**串行工作(sequencial or serial)**的。
對老闆而言,一方面他要調用員工,一方面要獲取員工的工作狀態,如果安排一個員工,並一直眼巴巴等待員工執行完成的結果,就是同步調用。
同步調用,這種事情可能發生在
FGA 抽卡
三崩子 抽老婆
按下那神聖的按鍵(調用),這時我們只會雙眼焦急的盯屏幕(幹不了別的事 而是等待),只見一道聖光緩緩輸出,我們還是不做任何事,直到老婆出現:)
沒事,我老婆不是抽卡出來的2333,saber 不支持任何辯駁 準備拔劍吧,少年
FPGA 阻塞賦值 非阻塞賦值
所以凡是幹活的(進程 命令 語句),後一個會因爲前一個事沒幹完,導致自己也幹不了(第一個阻塞第二個的)就稱爲阻塞,反之爲非阻塞,比如FPGA的阻塞賦值與非阻塞賦值。我們可以結合這個根源來加深理解。
我們設定a=55 b=c=0
(初始值)
阻塞賦值:前面語句(可以看作是被調用的語句 幹活的)執行完,纔可執行下一條語句;即:前面語句(理髮師1)的執行(b=a)阻塞了後面語句(理髮師2)的執行(c=b)。
上帝視角看來 2條語句順序執行
而我們是同步調用兩者的
兩個語句間 阻塞
always @(posedge clock)
begin
b = a;
c = b;
end
注意FPGA always@(posedge clock)
是吧clock的上升沿設爲敏感信號,每當上升沿到來,就執行always語句裏面的代碼。在同一個時鐘上升沿完成,如下圖仿真結果,從上到下分別是clock,rst,a,b,c 五個信號,請無視rst信號(第二個)。
非阻塞賦值:前面語句(理髮師1)的執行(b=a)不會阻塞後面(理髮師2)語句的執行(c=b)
always @(posedge i_clk)
begin
b <= a;
c <= b;
end
上帝視角看來 2條語句並序執行
而我們是異步調用兩者的
兩個語句間 非阻塞
第1個clock上升沿,
》a的值賦給b
》b的值賦給c
第二句,開始時,b仍然是初始值0,b還沒有更新,等到兩句並行執行結束
》b從a得到了55
》c從b那邊得到0
第2個clock上升沿,
》a的值賦給b
》b的值賦給c
並行執行完
》b從a得到了55
》c從b那邊得到55
所以c獲得a的值,需要2個clk完成。
如下圖仿真結果:從上到下分別是clock,rst,a,b,c 五個信號,請無視rst信號(第二個)。
其實非阻塞賦值,綜合synthesis出的是兩個鎖存器latch,而阻塞賦值是直接連線的(類似wire)。
python應用
非阻塞式執行 異步調用
#-*- utf-8 -*-
from time import sleep,time
from random import random
import os
from multiprocessing import Process
from multiprocessing import Pool
def ftask(task_name):
print("開始理髮",task_name)
start = time()
a = random()
sleep(a if(a>0.4) else a+0.4)
end = time()
return " {}發理完了,用時:{},進程id:{}".format(task_name,(end-start), os.getpid() )
list_barber = []
def fcallback(n):
list_barber.append(n)
if __name__ == '__main__':
pool = Pool(5)
task_set = ["Mr.A","Mr.B","Mr.C","Mr.D","Mr.E","Mr.F","Mr.G"]
for task in task_set:
pool.apply_async(ftask,args=(task,),callback=fcallback)
pool.close()
pool.join()
for barber in list_barber:
print(barber)
結果如下:
開始理髮 Mr.A
開始理髮 Mr.B
開始理髮 Mr.C
開始理髮 Mr.D
開始理髮 Mr.E
開始理髮 Mr.F
開始理髮 Mr.G
Mr.A發理完了,用時:0.7314853668212891,進程id:12224
Mr.B發理完了,用時:0.7336766719818115,進程id:18748
Mr.D發理完了,用時:0.8218517303466797,進程id:18736
Mr.E發理完了,用時:0.8295514583587646,進程id:9980
Mr.C發理完了,用時:0.998112678527832,進程id:20308
Mr.F發理完了,用時:0.4738035202026367,進程id:12224
Mr.G發理完了,用時:0.9274580478668213,進程id:18748
阻塞式調用 同步調用
#-*- utf-8 -*-
from time import sleep,time
from random import random
import os
from multiprocessing import Process
from multiprocessing import Pool
def ftask(task_name):
print("開始理髮",task_name)
start = time()
a = random()
sleep(a if(a>0.4) else a+0.4)
end = time()
print(" {}發理完了,用時:{},進程id:{}".format(task_name,(end-start), os.getpid() ))
list_barber = []
def fcallback(n):
list_barber.append(n)
if __name__ == '__main__':
pool = Pool(5)
task_set = ["Mr.A","Mr.B","Mr.C","Mr.D","Mr.E","Mr.F","Mr.G","Mr.H"]
for task in task_set:
pool.apply(ftask,args=(task,))
pool.close()
pool.join()
print("main process ended")
結果如下:
開始理髮 Mr.A
Mr.A發理完了,用時:0.5076336860656738,進程id:17828
開始理髮 Mr.B
Mr.B發理完了,用時:0.9321200847625732,進程id:19788
開始理髮 Mr.C
Mr.C發理完了,用時:0.47928452491760254,進程id:19548
開始理髮 Mr.D
Mr.D發理完了,用時:0.439760684967041,進程id:19112
開始理髮 Mr.E
Mr.E發理完了,用時:0.9770023822784424,進程id:11848
開始理髮 Mr.F
Mr.F發理完了,用時:0.45802879333496094,進程id:17828
開始理髮 Mr.G
Mr.G發理完了,用時:0.5110907554626465,進程id:19788
開始理髮 Mr.H
Mr.H發理完了,用時:0.7647738456726074,進程id:19548
main process ended
總結 六級單詞
敲黑板 單詞表:
正 | 中文 | 反 | 中文 |
---|---|---|---|
synchronous | 同步同時 | asynchronous | 異步 不同時 |
serial sequential | 串行 順序 | parallel concurrent | 並行併發 |
blocking | 阻塞 | non-blocking | 非阻塞 |
下一節我們就迎來了進程的組成部分——線程,特點,顯而易見更加硬核 更加深入的理解進程與線程:python 基礎(三) 線程 Threading GIL 線程同步