回调与多进程

时间:2021-04-02 11:30:08

大佬们的解释:

为了指定某函数(对象)在进入到某状态时要进行的操作,将该操作封装成一个函数,并将该函数指针作为参数传入。在这个动作中被传递的函数就叫做 回调函数。

回调函数的本质其实就是:
函数调用函数,或者说,就是嵌套函数,类似于嵌套for循环。
但是由于应用场景不同取了个这样的名字。感觉是为了区别于传统的函数调用感觉是为了区别于传统的函数调用
其实回调函数不太好理解的地方是他的应用场景。

通常的函数调用,调用者是需要知道被调函数作用的。也就是高层调用底层。
而回调函数这里,函数实际的调用者并不了解要调用的函数实际是什么,也就是高层要调用哪个函数实际是由低层决定的。因此叫做回调....


如果由底层的代码指定,那就是回调如果由底层的代码指定,那就是回调

当程序跑起来时,一般情况下,应用程序(application program)会时常通过API调用库里所预先备好的函数。但是有些库函数(library function)却要求应用先传给它一个函数,好在合适的时候调用,以完成目标任务。这个被传入的、后又被调用的函数就称为回调函数(callback function)。

主程序调用了API,但是使用API的过程中,还有主程序提供的函数。
比如相机在采集某些帧图像的时候,用户要进行某些处理,这个处理的功能就写在回调里面

用户自己的代码里不要自行调用回调函数
要让驱动或者系统调用,否则会出现问题的

可以认为系统代码是高层代码(主函数所在的位置),你写的代码的是底层代码(被系统调用的是”底层代码的其中一部分“)。通过回调的思路,系统可以预留一些位置(     )让你来指定,由他来调用。也就是底层代码干预了高层代码的执行

就好比说你领导要干一项工作,你能干,你某个同事也能干,领导说,小王,去干什么什么,这叫回调,
领导不关心你具体怎么干,
你只要干好了就行了
另外,并不是说我要来执行这个回调函数,系统决定什么时候来执行。
程序决定什么时候来执行


以下链接中的两个解释也很不错:

https://www.zhihu.com/question/56850315

https://www.cnblogs.com/hainan-zhang/p/6222552.html


然后看代码,代码来自:

https://www.cnblogs.com/qiangyuge/p/7455814.html

以下文字来自该参考链接:

需要回调函数的场景:

进程池中任何一个任务一旦处理完了,就立即告知主进程:我好了额,你可以处理我的结果了。主进程则调用一个函数去处理该结果,该函数即回调函数

我们可以把耗时间(阻塞)的任务放到进程池中,然后指定回调函数(主进程负责执行),这样主进程在执行回调函数时就省去了I/O的过程,直接拿到的是任务的结果。


一、非阻塞回调(即异步回调):

#一:使用进程池(非阻塞,apply_async)
#coding: utf-8
from multiprocessing import Process,Pool
import time

def func(msg):
    print( "msg:", msg)
    time.sleep(1)
    return msg

if __name__ == "__main__":
    pool = Pool(processes = 3)
    res_l=[]
    for i in range(10):
        msg = "hello %d" %(i)
        res=pool.apply_async(func, (msg, ))   #维持执行的进程总数为processes,当一个进程执行完毕后会添加新的进程进去
        res_l.append(res)
    print("==============================>") #没有后面的join,或get,则程序整体结束,进程池中的任务还没来得及全部执行完也都跟着主进程一起结束了

    pool.close() #关闭进程池,防止进一步操作。如果所有操作持续挂起,它们将在工作进程终止前完成
    pool.join()   #调用join之前,先调用close函数,否则会出错。执行完close后不会有新的进程加入到pool,join函数等待所有子进程结束

    print(res_l) #看到的是<multiprocessing.pool.ApplyResult object at 0x10357c4e0>对象组成的列表,而非最终的结果,但这一步是在join后执行的,证明结果已经计算完毕,剩下的事情就是调用每个对象下的get方法去获取结果
    for i in res_l:
        print(i.get()) #使用get来获取apply_aync的结果,如果是apply,则没有get方法,因为apply是同步执行,立刻获取结果,也根本无需get

#二:使用进程池(阻塞,apply)
#coding: utf-8
from multiprocessing import Process,Pool
import time

def func(msg):
    print( "msg:", msg)
    time.sleep(0.1)
    return msg

if __name__ == "__main__":
    pool = Pool(processes = 3)
    res_l=[]
    for i in range(10):
        msg = "hello %d" %(i)
        res=pool.apply(func, (msg, ))   #维持执行的进程总数为processes,当一个进程执行完毕后会添加新的进程进去
        res_l.append(res) #同步执行,即执行完一个拿到结果,再去执行另外一个
    print("==============================>")
    pool.close()
    pool.join()   #调用join之前,先调用close函数,否则会出错。执行完close后不会有新的进程加入到pool,join函数等待所有子进程结束

    print(res_l) #看到的就是最终的结果组成的列表
    for i in res_l: #apply是同步的,所以直接得到结果,没有get()方法
        print(i)

上面的代码中回调函数是func,从调用流程上看,回调的意思其实是在互相调用:

代码的主体调用了pool.apply,

而pool.apply也调用了func

他们在互相调用。

二、阻塞回调(即同步回调):

from multiprocessing import Pool
import os,time
def work(n):
    print('%s run' %os.getpid())
    time.sleep(3)
    return n**2

if __name__ == '__main__':
    p=Pool(3) #进程池中从无到有创建三个进程,以后一直是这三个进程在执行任务
    res_l=[]
    for i in range(10):
        res=p.apply(work,args=(i,)) #同步运行,阻塞、直到本次任务执行完毕拿到res
        res_l.append(res)
print(res_l)

上面的代码中回调函数是work,从调用流程上看,回调的意思其实是在互相调用:

代码的主体调用了p.apply,

而p.apply也调用了work