python基础系列 正在持续更新中:)
两个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的阻塞赋值与非阻塞赋值。我们可以结合这个根源来加深理解。
我们设定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)。
非阻塞式执行 异步调用
#-*- 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 线程同步