从异步函数调用普通函数与从异步函数等待协程有什么区别?

问题描述

  1. async def caller():
        await bar()
        print("finish")
    
    async def bar():
       // some code here
    
  2. async def caller():
        bar()
        print("finish")
    
    def bar():
       //some code here
    

在上面的示例中。两种情况下,调用者都必须等待bar()完成。对于这种情况,bar正常/协程有什么区别?如果我们要“等待”某些功能,为什么不只使用普通功能。

解决方法

简而言之

  • bar()直接调用该函数并返回其结果
  • await bar()计划在事件循环之前尽快执行它并返回结果。
,

区别在于第二个示例generate_from_frequencies是一个非异步函数,因此它本身无法等待任何东西。例如,如果您想从bar()中访问Web服务,那么在第一个示例中就不会有问题,只需使用aiohttp。在第二个示例中,这几乎是不可能的,因为需要从异步函数中使用异步库,而非异步库将在等待响应时阻塞整个事件循环。

如果我们要“等待”某些功能,为什么不只使用普通功能。

如果您等待的功能不需要与外界通信(例如,如果只是在字典中随机整理数据),那么它可以并且应该是正常功能。另一方面,如果需要执行IO,则应使用异步功能。

,

协程不能在简单的调用中运行,它需要在事件循环中运行。 事件循环将监听我们添加到事件池中的事件,并在事件触发时执行回调 而当它执行代码的“await”部分时,可能意味着有一些I/O bounds任务,这样事件循环就会继续下一个事件,这样就不会阻塞线程。

,

如果它不是async函数,则显然不需要await。并非您在async函数中调用的每个函数都必须async也必须await被赋值;您可以从async函数中调用常规的非异步函数。

整个异步模型都围绕事件循环工作。一次只能运行一项任务,事件循环会协调当前正在运行的任务。函数内部的await暂停该函数的执行,并允许在事件循环上运行另一个任务。因此,在此示例中:

async def caller():
    await bar()
    print('finish')

执行过程如下:

    在事件循环中调用
  1. caller()并对其进行调度,一旦有可用性,它将立即执行。
  2. 它调用bar(),以调度它在事件循环中的执行。
  3. await暂停执行caller
  4. 事件循环执行bar;假设它正在发出网络请求,因此在响应返回之前什么也不会发生,事件循环可以自由运行任何其他预定的异步任务…
  5. 网络响应返回,事件循环恢复执行bar
  6. bar结束,事件循环恢复执行caller

await的存在是为了协调异步任务的运行顺序以及什么任务取决于其他任务的结果。

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...