详细分析python中的 async 和 await(附Demo)

04-27 1699阅读

目录

  • 前言
  • 1. 基本知识
  • 2. Demo
    • 2.1 Demo1(同步)
    • 2.2 Demo2(错误)
    • 2.3 Demo3(不正确的异步)
    • 2.4 Demo4(正确异步)
    • 3. 完整版
    • 4. 拓展
      • 4.1 asyncio.create_task(coroutine)
      • 4.2 asyncio.gather(*coroutines_or_futures, return_exceptions=False)
      • 4.3 字符串拼接

        前言

        对于异步的基本知识推荐阅读我之前的文章:

        1. 详细讲解Python中的aioschedule定时任务操作
        2. java关于@Async异步调用详细解析附代码
        3. 【操作系统】线程与进程的深入剖析(全)
        4. 【操作系统】守护线程和守护进程的区别

        1. 基本知识

        在Python中,async和await是用于异步编程的关键字,引入了异步/协程(coroutine)的概念

        异步编程是一种处理并发任务的方式,使得程序能够在等待某些I/O操作(如文件读写、网络请求等)的同时继续执行其他任务,而不会发生阻塞

        • 异步(Asynchronous):在异步编程中,程序不会等待某些I/O操作完成,而是继续执行其他任务,待操作完成后再回来处理结果
        • 协程(Coroutine):协程是一种轻量级的线程,可以在执行过程中暂停并让出控制权,然后在需要时恢复执行

          使用协程可以更有效地利用系统资源,避免线程切换的开销

          作用:

          • 提高程序效率:异步编程可以充分利用I/O等待时间,使得程序在等待操作完成时能够继续执行其他任务,从而提高了整体程序的效率。
          • 改善用户体验:在网络编程中,异步操作可以避免阻塞用户界面,使得应用程序更加流畅。
          • 简化并发编程:通过使用async和await关键字,可以更方便地编写并发程序,避免了传统多线程编程中的锁和同步问题。

            2. Demo

            以下例子会一步步体现异步的重要性!

            2.1 Demo1(同步)

            为了比较异步,先给出同步的例子:

            from time import sleep
            def greet(name):
                print("Hello, " + name)
                sleep(2)  # 模拟一个耗时的操作
                print("Goodbye, " + name)
            # 运行主函数
            if __name__ == "__main__":
                greet("码农")
                greet("研究僧")
            

            执行的顺序如下:

            (这就是同步,需要等待上一个操作执行完)

            详细分析python中的 async 和 await(附Demo)

            2.2 Demo2(错误)

            为了引入异步,我们先使用这个代码进行演示:(以下为错误代码)

            from time import sleep
            async def greet(name):
                print("Hello, " + name)
                sleep(2)  # 模拟一个耗时的操作
                print("Goodbye, " + name)
            # 运行主函数
            if __name__ == "__main__":
                greet("码农")
                greet("研究僧")
            

            输出结果如下:

            F:\python_project\test\main.py:19: RuntimeWarning: coroutine 'greet' was never awaited
              greet("码农")
            RuntimeWarning: Enable tracemalloc to get the object allocation traceback
            F:\python_project\test\main.py:20: RuntimeWarning: coroutine 'greet' was never awaited
              greet("研究僧")
            RuntimeWarning: Enable tracemalloc to get the object allocation traceback
            

            截图如下:

            详细分析python中的 async 和 await(附Demo)

            通过实战完善知识点:

            在Python中,async和await是一对配合使用的关键字,用于定义异步函数和在异步函数中等待其他异步操作完成

            配合使用可以实现协程的特性,使得异步编程更加简洁和易于理解

            • async关键字:

              async用于定义一个异步函数,表明该函数是一个协程,可以在其中使用await关键字等待其他异步操作完成

              异步函数的执行不会阻塞事件循环,而是会立即返回一个协程对象。

            • await关键字:

              await用于在异步函数内部等待其他协程执行完成,后面通常跟着一个需要等待的协程对象

              当遇到await关键字时,事件循环会挂起当前的协程,并执行其他任务,直到等待的协程完成后才会恢复执行当前协程

              这两个关键字配合使用的好处在于:

              • 简化异步编程:使用async和await关键字可以使异步编程更加直观和易于理解,避免了回调函数和复杂的异步调度逻辑。

              • 实现协程:async和await的组合使得函数可以在执行过程中暂停并恢复,实现了协程的特性,可以更灵活地处理异步任务。

              • 提高可读性:使用async和await可以使异步代码更加清晰和可读,使得程序逻辑更易于理解和维护。

                2.3 Demo3(不正确的异步)

                修正为如下:(正确)

                import asyncio
                from time import sleep
                # 定义一个异步函数
                async def greet(name):
                    print("Hello, " + name)
                    sleep(2)  # 模拟一个耗时的操作
                    print("Goodbye, " + name)
                async def main():
                    await greet("码农")
                    await greet("研究僧")
                # 运行主函数
                if __name__ == "__main__":
                    asyncio.run(main())
                

                或者

                import asyncio
                # 定义一个异步函数
                async def greet(name):
                    print("Hello, " + name)
                    await asyncio.sleep(2)  # 模拟一个耗时的操作
                    print("Goodbye, " + name)
                async def main():
                    await greet("码农")
                    await greet("研究僧")
                # 运行主函数
                if __name__ == "__main__":
                    asyncio.run(main())
                

                这两者的输出都为如下:

                详细分析python中的 async 和 await(附Demo)

                光看上面的代码也只是同步输出,而不是异步输出的结果

                2.4 Demo4(正确异步)

                为了体现异步执行的效果,可以使用asyncio.create_task()创建任务并发执行

                import asyncio
                # 定义一个异步函数
                async def greet(name):
                    print("Hello, " + name)
                    await asyncio.sleep(2)  # 使用异步的sleep函数
                    print("Goodbye, " + name)
                # 执行异步函数
                async def main():
                    # 创建任务并发执行
                    task1 = asyncio.create_task(greet("码农"))
                    task2 = asyncio.create_task(greet("研究僧"))
                    # 等待所有任务完成
                    await asyncio.gather(task1, task2)
                # 运行主函数
                if __name__ == "__main__":
                    asyncio.run(main())
                

                截图如下:

                详细分析python中的 async 和 await(附Demo)

                3. 完整版

                完整版代码如下:

                import asyncio
                from datetime import datetime
                # 定义一个异步函数
                async def greet(name):
                    print("Hello, " + name + str(datetime.now()))
                    await asyncio.sleep(2)  # 使用异步的sleep函数
                    print("Goodbye, " + name + str(datetime.now()))
                # 执行异步函数
                async def main():
                    # 创建任务并发执行
                    task1 = asyncio.create_task(greet("码农"))
                    task2 = asyncio.create_task(greet("研究僧"))
                    # 等待所有任务完成
                    await asyncio.gather(task1, task2)
                if __name__ == "__main__":
                    start = datetime.now()  # 记录程序开始执行的时间
                    asyncio.run(main())  # 运行主函数
                    end = datetime.now()  # 记录程序结束执行的时间
                    print('elapsed time =', end - start)  # 输出执行时间
                

                输出结果如下:

                详细分析python中的 async 和 await(附Demo)

                4. 拓展

                对于上述代码,有个别函数拓展如下

                asyncio.create_task() 和 asyncio.gather() 是 Python 中 asyncio 模块中的两个重要函数,用于创建和管理协程任务。都用于在异步编程中管理多个协程的执行,但是有着不同的作用和用法。

                总的来说,asyncio.create_task() 用于并发执行多个协程任务,而 asyncio.gather() 用于等待多个协程任务的全部完成,并且可以收集执行结果

                这两个函数是 asyncio 中协程任务管理的重要工具

                4.1 asyncio.create_task(coroutine)

                • asyncio.create_task() 用于创建一个协程任务,并安排其立即执行

                  接受一个协程对象作为参数,并返回一个任务对象

                  该任务对象可以用来控制和管理该协程的执行,包括取消、等待其执行完成等

                  import asyncio
                  async def my_coroutine():
                      await asyncio.sleep(1)
                      print("Coroutine executed")
                  async def main():
                      task = asyncio.create_task(my_coroutine())
                      await task  # 等待任务执行完成
                  asyncio.run(main())
                  

                  以上 使用 asyncio.create_task() 可以方便地并发执行多个协程

                  4.2 asyncio.gather(*coroutines_or_futures, return_exceptions=False)

                  • asyncio.gather() 用于同时运行多个协程,并等待全部完成

                    接受一系列的协程对象(或者 Future 对象)作为参数,并返回一个协程对象,该协程对象会在所有给定的协程都执行完毕后完成

                    import asyncio
                    async def coro1():
                        await asyncio.sleep(1)
                        return "Coroutine 1"
                    async def coro2():
                        await asyncio.sleep(2)
                        return "Coroutine 2"
                    async def main():
                        result = await asyncio.gather(coro1(), coro2())
                        print(result)
                    asyncio.run(main())
                    

                    4.3 字符串拼接

                    对于输出函数来说,一般都由字符串组成

                    如果使用其他非字符串则需要进行转化

                    datetime.now()返回的是一个datetime对象,不能直接与字符串拼接

                    需要将datetime对象转换为字符串类型才能进行拼接

                    使用str()函数将datetime对象转换为字符串

                    print("Hello, " + name + ", 时间:" + str(datetime.now()))
                    

                    或者使用字符串的format()方法进行格式化输出

                    print("Hello, {}, 时间: {}".format(name, datetime.now()))
                    

                    或者使用 f-string 格式化字符串

                    print(f"Hello, {name}, 时间: {datetime.now()}")
                    

                    这些都是将datetime.now()的结果转换为字符串后再与其他字符串进行拼接的方法

VPS购买请点击我

文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。

目录[+]