• 阻塞非阻塞同步异步&异步回调


    阻塞非阻塞同步异步&异步回调

    阻塞与非阻塞是用来描述程序的状态

    阻塞:指调用结果返回之前,当前线程会被挂起(如遇到IO操作),函数只有在得到结果之后才会将阻塞的线程激活

    非阻塞:指不能立刻得到返回结果之前也会立刻返回,同时不会阻塞当前线程

    串行、并发与并行是用来描述处理任务的方式

    串行:程序按照自上而下的顺序执行

    并发:多个任务同时执行,本质上是在不同进程或线程间切换执行,由于速度快所以感觉是同时运行

    并发:真正意义上的多个任务同时执行

    同步与异步是指提交任务的方式

    同步:指的是提交任务后必须在原地等待,知道任务结束。此时任务还是激活的状态,所以并不是阻塞。

    异步:指的是提交任务后不需要在原地等待,可以继续往下执行代码。例如开启多线程多进程可以实现异步,会产生阻塞、

    异步效率会高于同步效率,但异步任务将导致一个问题:任务的发起方不知道任务何时结束。所以有以下两种解决方法:

    方法一:重复的隔一段时间就询问一次。效率低。并且无法及时获取结果,所以不推荐使用

    方法二:让任务的执行方主动通知(异步回调)。可以及时拿到任务的结果,推荐使用

    • 异步回调就是在发起任务时给任务绑定一个函数,在任务执行完后自动调用这个函数,把结果传给发起方(若发起方不关心任务结果,就不需要异步回调)

    异步回调使用

    # 线程中的异步回调
    import time
    from threading import Thread
    
    
    def task(callback):
        print("task start....")
        sum = 0
        for i in range(10000):
            sum += i
    
        time.sleep(2)
        callback(sum)
    
    
    # 回调函数,参数为任务的结果
    def callback(res):
        print("task result:",res)
    
    
    t = Thread(target=task,args=(callback,))
    t.start()
    print('over')
    
    task start....
    over
    
    task result: 49995000  # 这个结果在最后使用异步回调机制得到
    
    # 进程中的异步回调
    import time
    from multiprocessing import Process
    
    
    def task(callback):
        print("task start.....")
        sum = 0
        for i in range(10000):
            sum += i
        time.sleep(2)
        callback(sum)
    
    
    def callback(res):
        print("task result:",res)
    
    
    
    if __name__ == '__main__':
        p = Process(target=task,args=(callback,))
        p.start()
        print("over")
        
    over
    task start.....
    task result: 49995000    
    

    进程池&线程池的异步回调

    # 线程池中的异步回调
    import time
    from concurrent.futures import ThreadPoolExecutor
    
    def task(num):
        print("task starting.....")
        sum = 0
        for i in range(1000):
            sum += i
        time.sleep(2)
        print(num)
        return sum
    
    
    def callback(obj):
        print("task end:",obj.result())
    
    
    pool = ThreadPoolExecutor(2)
    res = pool.submit(task,123)
    res.add_done_callback(callable)  # 为任务绑定回调函数
    print("over")
    
    task starting.....
    over
    
    123
    ————————————————————————————————————————————————————————————
    # 线程池中的异步回调
    import time
    from concurrent.futures import ProcessPoolExecutor
    
    def task():
        print('task start....')
        time.sleep(2)
        print("task end")
        return "hello python"
    
    def callback(res):
        print("任务结果:",res.result())
    
    
    if __name__ == '__main__':
        p = ProcessPoolExecutor(2)
        res = p.submit(task)
        res.add_done_callback(callback)  # 为任务绑定回调函数
        print("over")
    
    over
    task start....
    task end
    任务结果: hello python 
    # 补充知识:
    # res = <Future at 0x21d2230a9b0 state=running>
    # res.result: <bound method Future.result of <Future at 0x21d2230a9b0 state=running>>
    # res.result(): hello python
    
    from concurrent.futures import ThreadPoolExecutor,ProcessPoolExecutor
    import time
    import os
    
    # pool = ThreadPoolExecutor(5)  # 括号内可以传参数指定线程池内的线程个数
    # # 也可以不传  不传默认是当前所在计算机的cpu个数乘5
    pool = ProcessPoolExecutor()  # 默认是当前计算机cpu的个数
    """
    池子中创建的进程/线程创建一次就不会再创建了
    至始至终用的都是最初的那几个
    这样的话节省了反复开辟进程/线程的资源
    """
    
    def task(n):
        print(n,os.getpid())  # 查看当前进程号
        time.sleep(2)
        return n**2
    
    
    def call_back(n):
        print('拿到了异步提交任务的返回结果:',n.result())
    """
    提交任务的方式
        同步:提交任务之后 原地等待任务的返回结果 期间不做任何事
        异步:提交任务之后 不等待任务的返回结果(异步的结果怎么拿???) 直接执行下一行代码
    """
    
    # pool.submit(task,1)  # 朝线程池中提交任务   异步提交
    # print('主')
    """
    异步回调机制:当异步提交的任务有返回结果之后,会自动触发回调函数的执行
    
    """
    if __name__ == '__main__':
    
        t_list = []
        for i in range(20):
            res = pool.submit(task,i).add_done_callback(call_back)  # 提交任务的时候 绑定一个回调函数 一旦该任务有结果 立刻执行对于的回调函数
            # print(res.result())  # 原地等待任务的返回结果
            t_list.append(res)
    
        # pool.shutdown()  # 关闭池子 等待池子中所有的任务执行完毕之后 才会往下运行代码
        # for p in t_list:
        #     print('>>>:',p.result())
    
  • 相关阅读:
    Redis 读后小感
    Redis学习笔记十:独立功能之监视器
    Redis学习笔记九:独立功能之慢查询日志
    Redis学习笔记八:独立功能之二进制位数组
    Please restart this script from an administrative PowerShell
    MSBUILD : error MSB3428: 未能加载 Visual C++ 组件“VCBuild.exe”
    Macaca之Android原理浅析
    Macaca 基础原理浅析
    您需要来自XXX的权限才能对此文件夹进行更改
    JS是按值传递还是按引用传递?
  • 原文地址:https://www.cnblogs.com/zuihoudebieli/p/11385115.html
Copyright © 2020-2023  润新知