您当前的位置:首页 > IT编程 > python
| C语言 | Java | VB | VC | python | Android | TensorFlow | C++ | oracle | 学术与代码 | cnn卷积神经网络 | gnn | 图像修复 | Keras | 数据集 | Neo4j | 自然语言处理 | 深度学习 | 医学CAD | 医学影像 | 超参数 | pointnet | pytorch | 异常检测 | Transformers | 情感分类 | 知识图谱 |

自学教程:浅谈Python协程asyncio

51自学网 2021-10-30 22:27:24
  python
这篇教程浅谈Python协程asyncio写得很实用,希望能帮到您。

一、协程

官方描述;
协程是子例程的更一般形式。 子例程可以在某一点进入并在另一点退出。 协程则可以在许多不同的点上进入、退出和恢复。 它们可通过 async def 语句来实现。 参见 PEP 492。

  • 协程不是计算机内部提供的,不像进程、线程,由电脑本身提供,它是由程序员人为创造的, 实现函数异步执行。
  • 协程(Coroutine),也可以被称为微线程,是一种用户太内的上下文切换技术,其实就是通过一个线程实现代码块相互切换执行。看上去像子程序,但执行过程中,在子程序内部可中断,然后转而执行别的子程序,在适当的时候再返回来接着执行。例如:
# 需要python3.7+import asyncioasync def main():    print('hello')    await asyncio.sleep(1)    print('world')asyncio.run(main())# 打印 "hello",等待 1 秒,再打印 "world"

注意:简单地调用一个协程并不会使其被调度执行,

直接main() 调用会有问题:

RuntimeWarning: coroutine 'main' was never awaited  main()RuntimeWarning: Enable tracemalloc to get the object allocation traceback

def func1():    print(1)    ...    print(2)    def func2():    print(3)    ...    print(4)func1()func2() # 结果:1 2 3 4

实现协程的方法:

  • greenlet,早期模块【不建议使用】
  • yield关键字,它是python的生成器,具有保存状态,切换到其他函数去执行,再切换回原函数的功能。
  • asyncio装饰器(python3.4引入)
  • async、await 关键字(python3.5)【推荐使用】

1.1 greenlet实现协程

# 第三方模块,因此需要安装pip install greenlet
from greenlet import greenletdef func1():    print(1)    gr2.switch()    print(2)    gr2.switch()def func2():    print(3)    gr1.switch()    print(4)gr1 = greenlet(func1)gr2 = greenlet(func2)gr1.switch()# 结果:1 3 2 4

1.2 yield关键字

def func1():    yield 1    yield from func2()    yield 2def func2():    yield 3    yield 4f1 = func1()for item in f1:    print(item)    # 结果:1 3 2 4

1.3 asynico装饰器

python3.4 及之后版本支持

DeprecationWarning: “@coroutine” decorator is deprecated since Python 3.8, use “async def”
翻译:@coroutine"装饰器自Python 3.8起已弃用,请使用"async def"代替

所以这个也不支持。

import asyncio@asyncio.coroutinedef func1():    print(1)    yield from asyncio.sleep(2)  # 遇到IO耗时操作,自动切换到tasks中其他任务,比如:网络IO,下载图片    print(2)@asyncio.coroutinedef func2():    print(3)    yield from asyncio.sleep(2)  # 遇到IO耗时操作,自动切换到tasks中其他任务,比如:网络IO,下载图片    print(4)tasks = [    asyncio.ensure_future(func1()),    asyncio.ensure_future(func2())]loop = asyncio.get_event_loop()loop.run_until_complete(asyncio.wait(tasks))# 结果: 1 3 2 4

1.4 async & await 关键字

import asyncioasync def func1():    print(1)    await asyncio.sleep(2)  # 遇到IO耗时操作,自动切换到tasks中其他任务,比如:网络IO,下载图片    print(2)async def func2():    print(3)    await asyncio.sleep(2)  # 遇到IO耗时操作,自动切换到tasks中其他任务,比如:网络IO,下载图片    print(4)tasks = [    asyncio.ensure_future(func1()),    asyncio.ensure_future(func2())]loop = asyncio.get_event_loop()loop.run_until_complete(asyncio.wait(tasks))

二、协程的意义

充分利用线程。在一个线程中如果遇到IO等待时间线程不会一直等待,利用空闲时间再去干点其他事情。

以下载三张图片为例:

普通方式(同步)下载:

import timeimport requestsdef download_image(url, img_name):    print("开始下载:", url)    # 发送网络请求,下载图片    response = requests.get(url)    print("下载完成")    # 图片保存到本地文件    file_name = str(img_name) + '.png'    with open(file_name, mode='wb') as file:        file.write(response.content)if __name__ == '__main__':    start = time.time()    url_list = [        'https://tse4-mm.cn.bing.net/th/id/OIP.866vRxQ8QvyDsrUuXiu7qwHaNK?w=182&h=324&c=7&o=5&pid=1.7',        'https://tse2-mm.cn.bing.net/th/id/OIP.HUcWtoYPG-z2pu4ityajbAHaKQ?w=182&h=252&c=7&o=5&pid=1.7',        'https://tse2-mm.cn.bing.net/th/id/OIP.MvncR0-Pt9hVxKTdrvD9dAHaNK?w=182&h=324&c=7&o=5&pid=1.7',        'https://tse1-mm.cn.bing.net/th/id/OIP._nGloaeMWbL7NB7Lp6SnXQHaLH?w=182&h=273&c=7&o=5&pid=1.7',        ]    img_name = 1    for item in url_list:        download_image(item, img_name)        img_name += 1    end = time.time()    print(end - start)     # 最终时间:7.25s

协程方式(异步)下载:

import aiohttpimport asyncioimport timeasync def fetch(session, url):    print("发送请求:", url)    async with session.get(url, verify_ssl=False) as response:        content = await response.content.read()        file_name = url.rsplit('_')[-1]        # print(file_name)        with open(file_name, mode='wb') as file_object:            file_object.write(content)        print("下载完成")async def main():    async with aiohttp.ClientSession() as session:        url_list = [            'https://www3.autoimg.cn/newsdfs/g26/M02/35/A9/120x90_0_autohomecar__ChsEe12AXQ6AOOH_AAFocMs8nzU621.jpg',            'https://www3.autoimg.cn/newsdfs/g26/M02/35/A9/120x90_0_autohomecar__ChsEe12AXQ6AOOH_AAFocMs8nzU621.jpg',            'https://www3.autoimg.cn/newsdfs/g26/M02/35/A9/120x90_0_autohomecar__ChsEe12AXQ6AOOH_AAFocMs8nzU621.jpg',            'https://www3.autoimg.cn/newsdfs/g26/M02/35/A9/120x90_0_autohomecar__ChsEe12AXQ6AOOH_AAFocMs8nzU621.jpg',        ]        tasks = [asyncio.ensure_future(fetch(session, url)) for url in url_list]        await asyncio.wait(tasks)if __name__ == '__main__':    start = time.time()    asyncio.get_event_loop().run_until_complete(main())    end = time.time()    print(end - start)    # 结果:0.05s

到此这篇关于浅谈Python协程的文章就介绍到这了,更多相关Python协程内容请搜索51zixue.net以前的文章或继续浏览下面的相关文章希望大家以后多多支持51zixue.net!


Python3接口性能测试实例代码
Python编解码问题及文本文件处理方法详解
万事OK自学网:51自学网_软件自学网_CAD自学网自学excel、自学PS、自学CAD、自学C语言、自学css3实例,是一个通过网络自主学习工作技能的自学平台,网友喜欢的软件自学网站。