浅谈Python协程asyncio


Posted in Python onJune 20, 2021

一、协程

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

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


async 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 greenlet


def 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 2


def func2():
    yield 3
    yield 4

f1 = 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.coroutine
def func1():
    print(1)
    yield from asyncio.sleep(2)  # 遇到IO耗时操作,自动切换到tasks中其他任务,比如:网络IO,下载图片
    print(2)

@asyncio.coroutine
def 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 asyncio


async 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 time
import requests

def 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 aiohttp
import asyncio
import time


async 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协程内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
Python的ORM框架SQLAlchemy入门教程
Apr 28 Python
详解Python中的条件判断语句
May 14 Python
Python抓取淘宝下拉框关键词的方法
Jul 08 Python
python使用psutil模块获取系统状态
Aug 27 Python
Python简单实现两个任意字符串乘积的方法示例
Apr 12 Python
基于Python log 的正确打开方式
Apr 28 Python
padas 生成excel 增加sheet表的实例
Dec 11 Python
Python使用pyserial进行串口通信的实例
Jul 02 Python
Python适配器模式代码实现解析
Aug 02 Python
tensorflow pb to tflite 精度下降详解
May 25 Python
cookies应对python反爬虫知识点详解
Nov 25 Python
用Python将GIF动图分解成多张静态图片
Jun 11 Python
Python3接口性能测试实例代码
Jun 20 #Python
使用Djongo模块在Django中使用MongoDB数据库
python自动计算图像数据集的RGB均值
详解如何用Python实现感知器算法
python中24小时制转换为12小时制的方法
Jun 18 #Python
用Python selenium实现淘宝抢单机器人
python中pandas对多列进行分组统计的实现
You might like
PHP基础陷阱题(变量赋值)
2012/09/12 PHP
Laravel搭建后台登录系统步骤详解
2016/07/26 PHP
分享一个漂亮的php验证码类
2016/09/29 PHP
2017年最新PHP经典面试题目汇总(上篇)
2017/03/17 PHP
浅谈PHP封装CURL
2019/03/06 PHP
Jquery+WebService 校验账号是否已被注册的代码
2010/07/12 Javascript
javascript仿qq界面的折叠菜单实现代码
2012/12/12 Javascript
Node.js中HTTP模块与事件模块详解
2014/11/14 Javascript
js实现div弹出层的方法
2014/11/20 Javascript
Javascript使用post方法提交数据实例
2015/08/03 Javascript
JQuery异步加载PartialView的方法
2016/06/07 Javascript
数据结构中的各种排序方法小结(JS实现)
2016/07/23 Javascript
js匿名函数使用&传参(实例)
2017/09/08 Javascript
浅谈JS和jQuery的区别
2019/03/27 jQuery
JavaScript This指向问题详解
2019/11/25 Javascript
Python最基本的输入输出详解
2015/04/25 Python
Python matplotlib 画图窗口显示到gui或者控制台的实例
2018/05/24 Python
Python定义一个跨越多行的字符串的多种方法小结
2018/07/19 Python
python游戏开发之视频转彩色字符动画
2019/04/26 Python
python 如何将数据写入本地txt文本文件的实现方法
2019/09/11 Python
爬虫代理池Python3WebSpider源代码测试过程解析
2019/12/20 Python
Python中使用aiohttp模拟服务器出现错误问题及解决方法
2020/10/31 Python
python中time包实例详解
2021/02/02 Python
HTML5注册页面示例代码
2014/03/27 HTML / CSS
为娇小女性量身打造:Petite Studio
2018/11/01 全球购物
人事主管岗位职责范本
2013/12/04 职场文书
中层干部岗位职责
2013/12/18 职场文书
大一军训感言
2014/01/09 职场文书
大型车展策划方案
2014/02/01 职场文书
地理教师岗位职责
2014/03/16 职场文书
超市仓管员岗位职责
2014/04/07 职场文书
交通事故和解协议书
2014/09/25 职场文书
解析在浏览器地址栏输入一个URL后发生了什么
2021/06/21 Servers
Win11筛选键导致键盘失灵怎么解决? Win11关闭筛选键的技巧
2022/04/08 数码科技
利用nginx搭建RTMP视频点播、直播、HLS服务器
2022/05/25 Servers
win sever 2022如何占用操作主机角色
2022/06/25 Servers