zoukankan      html  css  js  c++  java
  • 阻塞非阻塞同步异步&异步回调

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

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

    阻塞:指调用结果返回之前,当前线程会被挂起(如遇到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())
    
  • 相关阅读:
    PAT (Advanced Level) Practice 1100 Mars Numbers (20分)
    PAT (Advanced Level) Practice 1107 Social Clusters (30分) (并查集)
    PAT (Advanced Level) Practice 1105 Spiral Matrix (25分)
    PAT (Advanced Level) Practice 1104 Sum of Number Segments (20分)
    PAT (Advanced Level) Practice 1111 Online Map (30分) (两次迪杰斯特拉混合)
    PAT (Advanced Level) Practice 1110 Complete Binary Tree (25分) (完全二叉树的判断+分享致命婴幼儿错误)
    PAT (Advanced Level) Practice 1109 Group Photo (25分)
    PAT (Advanced Level) Practice 1108 Finding Average (20分)
    P6225 [eJOI2019]异或橙子 树状数组 异或 位运算
    P4124 [CQOI2016]手机号码 数位DP
  • 原文地址:https://www.cnblogs.com/zuihoudebieli/p/11385115.html
Copyright © 2011-2022 走看看