当前位置:   article > 正文

python3.8 异步 asyncio 执行顺序_python 两个异步函数如何保证顺序

python 两个异步函数如何保证顺序

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

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())
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

执行结果为:

started at 19:21:49
开始执行 first_fun 函数。
first_fun 函数执行结束。
开始执行 second_fun 函数。
second_fun 函数执行结束。
finished at 19:21:49
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

说明执行顺序就是 从上到下的执行顺序,即当代码运行到 (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())
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

执行结果为:

started at 19:29:04
开始执行 first_fun 函数。
first_fun 函数执行结束。
开始执行 second_fun 函数。
second_fun 函数执行结束。
finished at 19:29:09
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

可以看出,执行顺序和普通函数也没区别。执行时间,就是两个协程函数的总和。
说明: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())
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

执行结果为:

started at 19:40:34
=============
finished at 19:40:34
开始执行 first_fun 函数。
first_fun 函数执行结束。
开始执行 second_fun 函数。
second_fun 函数执行结束。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

说明:代码运行到 ⑴ 处,它就会开辟一个“协程分支”,被调用的 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())
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

执行结果为:

started at 19:56:24
=============
finished at 19:56:24
开始执行 first_fun 函数。
开始执行 second_fun 函数。
  • 1
  • 2
  • 3
  • 4
  • 5

从结果中看出,协程分支中有了可等待对象,但因为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())
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

运行结果为:

started at 20:10:00
=============
开始执行 first_fun 函数。
开始执行 second_fun 函数。
first_fun 函数执行结束。
finished at 20:10:02
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

此时 代码 ⑴ 的 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())
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

运行结果为:

started at 20:18:02
=============
开始执行 first_fun 函数。
开始执行 second_fun 函数。
first_fun 函数执行结束。
second_fun 函数执行结束。
finished at 20:18:05
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

此时获得的是完整的运行结果。因为这次 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')}")
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/102679
推荐阅读
相关标签
  

闽ICP备14008679号