python 基础(二)阻塞 非阻塞 同步 异步 应用于multiprocess.pool 进程池 以及EDA FPGA

阻塞与非阻塞执行 同步与异步调用 顺序与并序

两个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 非阻塞
发布了14 篇原创文章 · 获赞 11 · 访问量 1179

猜你喜欢

转载自blog.csdn.net/weixin_43178828/article/details/104083540