• 欢迎访问搞代码网站,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏搞代码吧

python协程asyncio的个人理解

python 搞java代码 3年前 (2022-06-29) 35次浏览 已收录 0个评论

目录
协程与工作
根本语法
协程的申明和运行
可期待对象
运行asyncio程序
创立工作
休眠
机制解析
运行的流程图示
协程与工作
python语境中,协程 coroutine 的概念有两个:协程函数、协程对象,协程对象由协程函数创立失去(相似于类实例化失去一个对象).

了解协程,最重要的是理解事件循环和工作执行的机制,上面是三个准则:

事件循环中,一直循环执行各个工作,若一个工作遇到await或者执行实现,则返回控制权给事件循环,这时候事件循环再去执行下一个工作
事件循环同一时刻只会运行一个工作
协程不会被退出事件循环的执行日程,只有被注册为工作之后,事件循环才能够通过工作来设置日程以便并发执行协程
根本语法
协程的申明和运行
应用async def语句定义一个协程函数,但这个函数不可间接运行

async def aaa():
    print('hello')

print(aaa())

# 输入----------------------------------
<coroutine object aaa at 0x7f4f9a9dfec0>
/root/Project/test01/test2.py:4: RuntimeWarning: coroutine 'aaa' was never awaited
  print(aaa())
RuntimeWarning: Enable tracemalloc to get the object allocation traceback

如何运行一个协程呢,有三种形式:

1.应用asyncio.run()函数,可间接运行

import asyncio

async def aaa():
    print('hello')

asyncio.run(aaa())
# 输入-------------------------
hello

2.应用await进行异步期待
在协程函数中最重要的性能是应用await语法期待另一个协程,这将挂起以后协程,直到另一个协程返回后果。

await的作用:挂起 coroutine 的执行以期待一个 awaitable 对象。 只能在 coroutine function 外部应用。

import asyncio

async def aaa():
    print('hello')

async def main():
    await aaa()

asyncio.run(main())

3.应用asyncio.create_task() 函数来创立一个工作,放入事件循环中

import asyncio

async def aaa():
    print('hello')

async def main():
    asyncio.create_task(aaa())

asyncio.run(main())

可期待对象
下面说过,协程函数中最重要的性能是应用await语法期待另一个协程,这将挂起以后协程,直到另一个协程返回后果。(重要,反复一遍)

await前面须要跟一个可期待对象(awaitable),有上面三种可期待对象:

协程:包含协程函数和协程对象
工作:通过asyncio.create_task()函数将协程打包为一个工作
Futures:非凡的 低层级 可期待对象,示意一个异步操作的 最终后果
运行asyncio程序
asyncio.run(coro, *, debug=False)

传入协程coroutine coro ,创立事件循环,运行协程返回后果,并在完结时敞开,该当被用作 asyncio 程序的主入口点。

创立工作
asyncio.create_task(coro, *, name=None)

将 coro 协程 打包为一个 Task 排入日程筹备执行。返回 Task 对象。

休眠
coroutine asyncio.sleep(delay, result=None, *, loop=None)

阻塞 delay 指定的秒数,该协程总是会挂起当前任务,以容许其余工作运行

机制解析
通过官网的两段代码,来具体解析一下协程的运行机制。

官网两个代码如下,留神看输入差别:

代码1,通过协程对象来执行

import asyncio
import time

async def say_after(delay, what):
    await asyncio.sleep(delay)
    print(what)

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

    await say_after(1, 'hello')
    await say_after(2, 'world')

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

asyncio.run(main())                # 1: 创立事件循环,传入入口点main()协程对象,此时生成一个对应的task

输入为

started at 17:13:52
hello
world
finished at 17:13:55

代码2,通过工作来执行

import asyncio
import time

async def say_after(delay, what):
    await asyncio.sleep(delay)
    print(what)

async def main():
    task1 = asyncio.create_task(
        say_after(1, 'hello'))

    task2 = asyncio.create_task(
        say_after(2, 'world'))

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

    await task1
    await task2

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

asyncio.run(main())

输入:

started at 17:14:32
hello
world
finished at 17:14:34

留神到运行工夫比前一个代码快1秒,上面阐明为什么呈现这种状况(文字比拟多)。

代码一的运行逻辑:

asyncio.run(main()) 启动一个事件循环,将入口点main()协程对象传入,生成一个对应的工作task_main;

事件循环运行工作task_main,而后执行第1条代码:print(f”started at {time.strftime(‘%X’)}”);

接着执行第2条代码:await say_after(1, ‘hello’),第2条代码首先生成一个say_after(1, ‘hello’)协程对象,同时生成该协程对象对应的task_1;

因为await语法,task_main工作将控制权返回给事件循环,同时通知事件循环须要期待task1能力持续运行;

事件循环取得控制权后,发现此时有两个工作task_main和task1,同时task_main在期待task1,于是会去执行task1工作;

task1工作将执行第1条代码:await asyncio.sleep(1),同样会生成asyncio.sleep(1)协程对象,以及对应的工作task2,同时因await语法将控制权返回给事件循环;

事件循环取得控制权后,发现此时有三个工作task_main、task1、task2,因为task_main、task1都处于期待状态,于是执行task3;

task3在1秒后运行实现,返回控制权给事件循环;

事件循环取得控制权,发现此时有两个工作task_main和task1,同时task_main在期待task1,于是会去执行task1工作;

task1工作执行第2条代码:print(‘hello’),执行实现后,工作也运行完结,将控制权返回给事件循环;

事件循环取得控制权后,发现此时有一个工作task_main,于是接着执行下一条代码:await say_after(2, ‘world’),持续反复上述过程,直到这个协程工作完结;

task_main执行最初一条代码;

事件循环敞开退出;

代码二的运行逻辑:

asyncio.run(main()) 启动一个事件循环,将入口点main()协程对象传入,生成一个对应的工作task_main;

事件循环运行工作task_main,而后执行前几条代码,创立两个工作task1、task2,并注册到事件循环中(此时事件循环一共有3个task),随之执行程序直到await;

第一个await:await task1,这里会阻塞当前任务task_main并将控制权返回给事件循环,事件循环获取控制权,安顿执行下一个工作task1;

task1工作开始执行,直至遇到await asyncio.sleep(1),asyncio.sleep(1)协程对象开始异步执行,同时task1返回控制权给事件循环,事件循环获取控制权后安顿执行下一个工作task2;

task2工作开始执行,直至遇到await asyncio.sleep(2),asyncio.sleep(2)协程对象开始异步执行,同时task2返回控制权给事件循环,事件循环获取控制权后安顿执行下一个工作;

此时3个工作均处于await状态,事件循环放弃期待;

1秒后asyncio.sleep(1)执行实现,task1勾销阻塞,事件循环将安顿task1执行,task1执行实现后返回控制权给事件循环,此时事件循环中一共两个工作task_main、task2。

此时task2工作处于await状态,而task_main也勾销了阻塞,事件循环安顿task_main执行,执行一行代码后遇到await task2,于是返回控制权给事件循环;

此时2个工作均处于await状态,事件循环放弃期待;

1秒后asyncio.sleep(2)执行实现,task2勾销阻塞,事件循环将安顿task2执行,task2执行实现后返回控制权给事件循环,此时事件循环中只剩工作task_main;

于是事件循环安顿task_main执行,task_main执行实现,asyncio.()函数收到信息也完结运行,整个程序完结

运行的流程图示
(工作就绪后,就期待事件循环来调用了,此时须要await来阻塞主工作task_main,否则控制权始终在task_main手上,导致task_main工作执行实现,run()收到main()执行完结的音讯后,事件循环也敞开并完结,程序也将退出)

其实将第2个代码中的await task1删除,只保留await task2,后果中的输入雷同,并耗费雷同的总工夫。但只保留await task1的话,将没有task2的输入;
如果将第2个代码中的await task1和await task2都删除,换成await asyncio.sleep(3),一样会打印雷同输入,不过总工夫会变为3秒;

其中的起因须要了解协程的工作机制(事件循环和控制权)

以上就是全部内容,心愿对大家有所帮忙学习,


搞代码网(gaodaima.com)提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发送到邮箱[email protected],我们会在看到邮件的第一时间内为您处理,或直接联系QQ:872152909。本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:python协程asyncio的个人理解

喜欢 (0)
[搞代码]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址