zoukankan      html  css  js  c++  java
  • 回调函数

    回调函数

    百度百科说:回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

    通俗理解就是:把一个函数作为参数传给另一个函数,第一个函数称为回调函数。这个被传入的参数其实是函数指针,即指向一个函数的指针(地址)。在python中,指针的概念被淡化

    阻塞非阻塞同步异步

    在执行的角度

    阻塞:程序运行时遇到了IO,程序挂起,cpu被切走.
    非阻塞:程序没有遇到I0,程序遇到10但是我通过某种手段,让cpu 强行运行我的程序.

    在发起的角度

    同步:提交-个任务 自任务开始运行直到此任务结束(可能有I0),返回一个返回值之后,我在提交下一个任务.
    异步:一次提交多个任务然后我就直接执行下一行代码.

    返回值回收的方式

    同步调用

    # 同步调用 获取结果后在发出下一个
    # 函数的返回值就是结果 一个任务是通过一个函数实现的,任务完成了他的返回值就是数的返回值.
    # obj.result()必须使其等到这个任务完成后,返回了结果之后,在执行下一个任务.
    # pool.shutdown(wait=True)
    # shutdown: 让我的主进程等待进程池中所有的子进程都结束任务之后,在执行,有点类似与join.
    # shutdown:在上一个进程池没有完成所有的任务之前,不允许添加新的任务,
    from concurrent.futures import ProcessPoolExecutor
    import time
    import random
    import os
    def task(i):
        print(f'{os.getpid()}开始')
        time.sleep(random.randint(1,3))
        print(f'{os.getpid()}结束')
        return i
    if __name__ == '__main__':
        pool=ProcessPoolExecutor(5)
        for i in range(10):
            obj=pool.submit(task,i)
            print(f'任务结果{obj.result()}')
        pool.shutdown(wait=True)
        print('我是主进程')
    

    异步调用

    第一种 异步调用 异步发出 所有任务完结后统一回收

    #异步调用 异步发出 所有任务完结后统一回收
    # 函数的返回值就是结果 一个任务是通过一个函数实现的,任务完成了他的返回值就是数的返回值.
    # obj是一个动态对象,返回的当前的对象的状态,有可能运行中,可能(就绪阻塞),还可能是结束了.
    # obj.result()必须使其等到这个任务完成后,返回了结果之后,在执行下一个任务.
    # pool.shutdown(wait=True)
    # shutdown: 让我的主进程等待进程池中所有的子进程都结束任务之后,在执行,有点类似与join.
    # shutdown:在上一个进程池没有完成所有的任务之前,不允许添加新的任务,
    from concurrent.futures import ProcessPoolExecutor
    import time
    import random
    import os
    def task(i):
        print(f'{os.getpid()}开始')
        time.sleep(random.randint(1,3))
        print(f'{os.getpid()}结束')
        return i
    if __name__ == '__main__':
        pool=ProcessPoolExecutor(5)
        l1=[]
        for i in range(10):
            obj=pool.submit(task,i)
            l1.append(obj)
        pool.shutdown(wait=True)
        for i in l1:
            print(f'执行结果{i.result()}')
        print('我是主进程')
    

    异步调用+回调函数

    版本1

    # 版本一 模拟爬虫:
    #     1. 异步发出10个任务,并发的执行,但是统一的接收所有的任务的返回值.(效率低,不能实时的获取结果)
    #     2. 分析结果流程是串行,影响效率.
    from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor
    import time
    import random
    import os
    import requests
    def task(url):
        ret=requests.get(url)
        if ret.status_code==200:
            return ret.text
    def parse(content):
        print(f'池里面的id  ---{os.getpid()}')
        return len(content)
    if __name__ == '__main__':
        url_list = [
                'http://www.baidu.com',
                'http://www.JD.com',
                'http://www.JD.com',
                'http://www.JD.com',
                'http://www.taobao.com',
                'https://www.cnblogs.com/jin-xin/articles/7459977.html',
                'https://www.luffycity.com/',
                'https://www.cnblogs.com/jin-xin/articles/9811379.html',
                'https://www.cnblogs.com/jin-xin/articles/11245654.html',
                'https://www.sina.com.cn/',
    
            ]
        pool=ThreadPoolExecutor(2)
        obj_list=[]
        for url in url_list:
            obj=pool.submit(task,url)
            obj_list.append(obj)
        pool.shutdown(wait=True)
        for res in obj_list:
            print(parse(res.result()))
        print(f'主{os.getpid()}')
    

    版本2

    针对版本一的缺点2,改进,让串行编程并发或者并行.
    1 在开一个线程进程池,并发并行的处理. 再开一个线程进程池,开销大.
    2 将原来的任务扩大,
    版本二:
    线程池设置4个线程, 异步发起10个任务,每个任务是通过网页获取源码+数据分析, 并发执行,
    最后将所有的结果展示出来.
    耦合性增强了.
    并发执行任务,此任务最好是IO阻塞,才能发挥最大的效果
    from concurrent.futures import ProcessPoolExecutor,ThreadPoolExecutor
    import time
    import random
    import os
    import requests
    def task(url):
        ret = requests.get(url)
        if ret.status_code == 200:
            return parse(ret.text)
    def parse(content):
        return len(content)
    if __name__ == '__main__':
        url_list = [
                'http://www.baidu.com',
                'http://www.JD.com',
                'http://www.JD.com',
                'http://www.JD.com',
                'http://www.taobao.com',
                'https://www.cnblogs.com/jin-xin/articles/7459977.html',
                'https://www.luffycity.com/',
                'https://www.cnblogs.com/jin-xin/articles/9811379.html',
                'https://www.cnblogs.com/jin-xin/articles/11245654.html',
                'https://www.sina.com.cn/',
    
            ]
    if __name__ == '__main__':
        pool = ThreadPoolExecutor(4)
        obj_list = []
        for url in url_list:
            obj = pool.submit(task, url)
            obj_list.append(obj)
        pool.shutdown(wait=True)
        for res in obj_list:
            print(res.result())
    

    版本3 最终版

    # 版本三:
    # 基于 异步调用回收所有任务的结果我要做到实时回收结果,
    # 并发执行任务每个任务只是处理IO阻塞的,不能增加新的功能.
    # 异步调用 + 回调函数 回调函数没有返回值 obj.add_done_callback(parse)
    # obj是一个动态对象,返回的当前的对象的状态,有可能运行中,可能(就绪阻塞),还可能是结束了.
    注意事项
        线程池设置4个线程, 异步发起10个任务,每个任务是通过网页获取源码, 并发执行,
        当一个任务完成之后,将parse这个分析代码的任务交由剩余的空闲的线程去执行,你这个线程继续去处理其他任务.
        如果进程池+回调: 回调函数由主进程去执行.
        如果线程池+回调: 回到函数由空闲的线程去执行.
    from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor
    import time
    import random
    import os
    import requests
    def task(url):
        ret = requests.get(url)
        if ret.status_code == 200:
            return ret.text
            
    def parse(obj):
        print(len(obj.result()))
    
    
    if __name__ == '__main__':
    
        # 开启线程池,并发并行的执行
        url_list = [
            'http://www.baidu.com',
            'http://www.JD.com',
            'http://www.JD.com',
            'http://www.JD.com',
            'http://www.taobao.com',
            'https://www.cnblogs.com/jin-xin/articles/7459977.html',
            'https://www.luffycity.com/',
            'https://www.cnblogs.com/jin-xin/articles/9811379.html',
            'https://www.cnblogs.com/jin-xin/articles/11245654.html',
            'https://www.sina.com.cn/',
    
        ]
        pool = ThreadPoolExecutor(4)
        for url in url_list:
            obj = pool.submit(task, url)
            obj.add_done_callback(parse)
    
    from concurrent.futures import ThreadPoolExecutor
    def task(x,y):
        return x*y
    def task1(obj,):
        print(f'计算结果{obj.result()}--------')
    if __name__ == '__main__':
        pool=ThreadPoolExecutor(5)
        for i in range(5):
            obj=pool.submit(task,5,6)
            obj.add_done_callback(task1)
    

    回调函数总结

    当一个任务完成之后,将parse这个分析代码的任务交由剩余的空闲的线程去执行,你这个线程继续去处理其他任务

    如果进程池+回调: 回调函数由主进程去执行.

    如果线程池+回调: 回到函数由空闲的线程去执行.

    其余小知识

    导入第3方模块

    终端导入

    添加环境变量把c:Python36Scripts添加到环境变量
    在cmd输入 pip install requests
    就可以添加 requests模块了
    

    cpythom导入

    file---Settings----Project:  ---Project Interpreter---旁边的加号
    

    re模块的爬虫

    #浏览器工作原理,向服务端发送一个请求,服务端验证你的请求,如果正确,给你的浏览器返回一个文件,
    #浏览器接收到文件,将文件里面的代码渲染成你看到的漂亮美丽的模样。
    #什么叫爬虫?
    # 1.利用代码模拟一个浏览器,进行浏览器的工作流程得到一堆源代码.
    # 2.对源代码进行数据清洗得到我想要数据.
    import requests
    ret=requests.get('http://www.baidu.com')
    if ret.status_code == 200:
        print(ret.text)
    

    小问题

    # 异步 回调是一回事儿?
    # 异步站在发布任务的角度,
    # 站在接收结果的角度: 回调函数 按顺序接收每个任务的结果,进行下一步处理.
    # 异步 + 回调:
    # 异步处理的IO类型.
    # 回调处理非IO
    
  • 相关阅读:
    整理 修改功能测试点
    centos 修改yum镜像源
    修改Docker容器的时间和宿主机一致
    Postgre Invalid command l;. Try ? for help.
    RGB渐变算法(JavaScript)
    docker postgre&postgis
    activiti+spring boot 报错: java.lang.NoClassDefFoundError: org/springframework/core/log/LogMessage
    Docker 创建 Postgre
    Jenkins+Gitlab+Maven 远程部署
    docker安装centos并ssh连接
  • 原文地址:https://www.cnblogs.com/saoqiang/p/12388501.html
Copyright © 2011-2022 走看看