python3.8 异步 asyncio 执行顺序

先看几种协程的执行情况:

1、 协程函数中没有 await,即没有可等待对象。且 调用函数 main() 也是直接用 await 调用,即不先创建 task。
import asyncio
import time

async def first_fun(delay):
    print('开始执行 first_fun 函数。')
    # await asyncio.sleep(delay)        # 注释掉,使其没有可等待对象。
    print('first_fun 函数执行结束。')
    return delay

async def second_fun(delay):
    print('开始执行 second_fun 函数。')
    # await asyncio.sleep(delay)
    print('second_fun 函数执行结束。')
    return delay

async def main():    
    print(f"started at {time.strftime('%X')}")

    await first_fun(2)      # ⑴
    await second_fun(3)		# ⑵

    print(f"finished at {time.strftime('%X')}")

asyncio.run(main())

执行结果为:

started at 19:21:49
开始执行 first_fun 函数。
first_fun 函数执行结束。
开始执行 second_fun 函数。
second_fun 函数执行结束。
finished at 19:21:49

说明执行顺序就是 从上到下的执行顺序,即当代码运行到 (1)处时,它会先把(1)引用的函数运行结束,才会再运行(2),和普通函数调用效果一样。

2、 协程函数中加入可等待对象,这里用 asyncio.sleep()进行模拟。
import asyncio
import time

async def first_fun(delay):
    print('开始执行 first_fun 函数。')
    await asyncio.sleep(delay)
    print('first_fun 函数执行结束。')
    return delay

async def second_fun(delay):
    print('开始执行 second_fun 函数。')
    await asyncio.sleep(delay)
    print('second_fun 函数执行结束。')
    return delay

async def main():
    print(f"started at {time.strftime('%X')}")

    await first_fun(2)
    await second_fun(3)

    # first = asyncio.create_task(first_fun(2))
    # second = asyncio.create_task(second_fun(3))

    print(f"finished at {time.strftime('%X')}")

asyncio.run(main())

执行结果为:

started at 19:29:04
开始执行 first_fun 函数。
first_fun 函数执行结束。
开始执行 second_fun 函数。
second_fun 函数执行结束。
finished at 19:29:09

可以看出,执行顺序和普通函数也没区别。执行时间,就是两个协程函数的总和。
说明:main() 函数中直接用 await 调用协程函数,就是普通的函数调用。

3、 main() 函数中创建task(), 但调用的协程函数中没有 await 可等待对象。main 中也没有用 await 来引用 task。
import asyncio
import time

async def first_fun(delay):
    print('开始执行 first_fun 函数。')
    # await asyncio.sleep(delay)      # 注释掉,使其没有可等待对象。
    print('first_fun 函数执行结束。')
    return delay

async def second_fun(delay):
    print('开始执行 second_fun 函数。')
    # await asyncio.sleep(delay)
    print('second_fun 函数执行结束。')
    return delay

async def main():
    print(f"started at {time.strftime('%X')}")

    first = asyncio.create_task(first_fun(2))      # ⑴
    print('=============')
    second = asyncio.create_task(second_fun(3))    # ⑵

    print(f"finished at {time.strftime('%X')}")

asyncio.run(main())

执行结果为:

started at 19:40:34
=============
finished at 19:40:34
开始执行 first_fun 函数。
first_fun 函数执行结束。
开始执行 second_fun 函数。
second_fun 函数执行结束。

说明:代码运行到 ⑴ 处,它就会开辟一个“协程分支”,被调用的 first_fun(2) 会进入那个“分支”运行,然后马上运行下面的代码,不会影响 “主协程” 的运行脚步。

4、 main() 函数中创建task(), 调用的协程函数中有 await 可等待对象。 但 main 中也没有用 await 来引用 task。
import asyncio
import time

async def first_fun(delay):
    print('开始执行 first_fun 函数。')
    await asyncio.sleep(delay)          # 加入模拟的可等待对象。
    print('first_fun 函数执行结束。')
    return delay

async def second_fun(delay):
    print('开始执行 second_fun 函数。')
    await asyncio.sleep(delay)
    print('second_fun 函数执行结束。')
    return delay

async def main():
    print(f"started at {time.strftime('%X')}")

    first = asyncio.create_task(first_fun(2))
    print('=============')
    second = asyncio.create_task(second_fun(3))


    print(f"finished at {time.strftime('%X')}")

asyncio.run(main())

执行结果为:

started at 19:56:24
=============
finished at 19:56:24
开始执行 first_fun 函数。
开始执行 second_fun 函数。

从结果中看出,协程分支中有了可等待对象,但因为main函数中没有用 await来引用 task,所以就获取不到协程分支中 等待 运行之后的结果了。 因为 还没还没等到支协程返回结果,主线程已经结束了。

5、 main() 函数中创建task(), 但调用的协程函数中有 await 可等待对象。 main 中,只用 await 来引用 了一个task,等待2秒的那个 first。
import asyncio
import time

async def first_fun(delay):
    print('开始执行 first_fun 函数。')
    await asyncio.sleep(delay)
    print('first_fun 函数执行结束。')
    return delay

async def second_fun(delay):
    print('开始执行 second_fun 函数。')
    await asyncio.sleep(delay)
    print('second_fun 函数执行结束。')
    return delay

async def main():
    print(f"started at {time.strftime('%X')}")

    first = asyncio.create_task(first_fun(2))
    print('=============')
    second = asyncio.create_task(second_fun(3))
    
    await first      # ⑴

    print(f"finished at {time.strftime('%X')}")

asyncio.run(main())

运行结果为:

started at 20:10:00
=============
开始执行 first_fun 函数。
开始执行 second_fun 函数。
first_fun 函数执行结束。
finished at 20:10:02

此时 代码 ⑴ 的 await 在等待接收 first_fun 协程运行结束, 但没有等待 second_fun,所以 还没运行到 second_fun 函数执行结束,主线程已经结束了。

6、 main() 函数中创建task(), 但调用的协程函数中有 await 可等待对象。 main 中,只用 await 来引用 了一个task,等待3秒的那个second。
import asyncio
import time

async def first_fun(delay):
    print('开始执行 first_fun 函数。')
    await asyncio.sleep(delay)
    print('first_fun 函数执行结束。')
    return delay

async def second_fun(delay):
    print('开始执行 second_fun 函数。')
    await asyncio.sleep(delay)
    print('second_fun 函数执行结束。')
    return delay

async def main():
    print(f"started at {time.strftime('%X')}")

    first = asyncio.create_task(first_fun(2))
    print('=============')
    second = asyncio.create_task(second_fun(3))

    # await first    # ⑴
    await second


    print(f"finished at {time.strftime('%X')}")

asyncio.run(main())

运行结果为:

started at 20:18:02
=============
开始执行 first_fun 函数。
开始执行 second_fun 函数。
first_fun 函数执行结束。
second_fun 函数执行结束。
finished at 20:18:05

此时获得的是完整的运行结果。因为这次 await 是等待 second 的运行结束。当等待3秒的second结束时,等待2秒的first已经提前结束了。所以此时 如果代码 ⑴ 即使不注释掉,运行结果也是一样的。

最后总结:

main()函数中:
asyncio.create_task():就相当于开启了一个线程。
await :        相当用线程的 join,等待协程的运行结束,再继续运行之后的代码。

如果协程最后有 return 的返回值,可以这样获取返回值:

async def main():
    print(f"started at {time.strftime('%X')}")

    first = asyncio.create_task(first_fun(2))
    second = asyncio.create_task(second_fun(3))

    await first
    s = await second    # 获取协程的返回值。
    print(s)

    print(f"finished at {time.strftime('%X')}")
  • 4
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Python中的异步编程模块是asyncioasyncio提供了一种基于协程的异步编程方式,使得在处理IO密集型任务时能够更高效地利用CPU资源。 在asyncio中,可以通过定义```async def```关键字来定义异步函数异步函数可以使用```await```关键字来等待其他异步函数的执行结果,并且可以在等待的过程中让出CPU资源,执行其他任务。通过这种方式,可以实现并发执行多个异步任务。 在异步代码中,通常使用事件循环(event loop)来调度和执行异步任务。事件循环会不断地从任务队列中获取任务,并将其发送给可执行的协程进行执行。在执行过程中,如果遇到了IO操作,如网络请求或文件读写,协程会将其交给事件循环处理,并继续执行其他任务。当IO操作完成后,事件循环会将结果返回给协程,协程继续执行后面的代码。 为了实现异步操作,可以使用async with语句来创建一个异步上下文管理器。异步上下文管理器可以通过定义```__aenter__```和```__aexit__```方法来控制进入和退出异步上下文的操作。在进入异步上下文时,可以执行一些准备工作,比如建立数据库连接;在退出异步上下文时,可以执行一些清理工作,比如关闭数据库连接。 另外,在处理多个URL请求时,可以使用asyncio的Future对象来包装异步函数,并将Future对象列表作为任务传递给事件循环。这样可以实现并发处理多个URL请求,提高程序的执行效率。 总之,asyncioPython中处理异步编程的重要模块,它提供了一种基于协程的异步编程方式,可以在IO密集型任务中提高程序的执行效率。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [python asyncio异步编程](https://blog.csdn.net/weixin_45859193/article/details/119930305)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [python异步编程之asyncio(百万并发)](https://blog.csdn.net/m0_72557783/article/details/128322661)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值