浅谈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自动化测试之从命令行运行测试用例with verbosity
Sep 28 Python
详细解析Python中的变量的数据类型
May 13 Python
python如何实现远程控制电脑(结合微信)
Dec 21 Python
python 随机数使用方法,推导以及字符串,双色球小程序实例
Sep 12 Python
Python学习笔记之if语句的使用示例
Oct 23 Python
python实现守护进程、守护线程、守护非守护并行
May 05 Python
python3实现windows下同名进程监控
Jun 21 Python
浅谈python连续赋值可能引发的错误
Nov 10 Python
Python解决线性代数问题之矩阵的初等变换方法
Dec 12 Python
python的pytest框架之命令行参数详解(下)
Jun 27 Python
Python读取xlsx文件的实现方法
Jul 04 Python
python爬取某网站原图作为壁纸
Jun 02 Python
Python3接口性能测试实例代码
Jun 20 #Python
使用Djongo模块在Django中使用MongoDB数据库
python自动计算图像数据集的RGB均值
详解如何用Python实现感知器算法
python中24小时制转换为12小时制的方法
Jun 18 #Python
用Python selenium实现淘宝抢单机器人
python中pandas对多列进行分组统计的实现
You might like
mysql alter table命令修改表结构实例详解
2016/09/24 PHP
PHP实现打包下载文件的方法示例
2017/10/07 PHP
Yii2.0框架behaviors方法使用实例分析
2019/09/30 PHP
JQuery 常用方法基础教程
2009/02/06 Javascript
CutePsWheel javascript libary 控制输入文本框为可使用滚轮控制的js库
2010/02/07 Javascript
简单的jquery左侧导航栏和页面选中效果
2014/08/21 Javascript
详解jQuery UI库中文本输入自动补全功能的用法
2016/04/23 Javascript
Bootstrap3 input输入框插入glyphicon图标的方法
2016/05/16 Javascript
jQuery 插件封装的方法
2016/11/16 Javascript
AngularJS基于http请求实现下载php生成的excel文件功能示例
2018/01/23 Javascript
Vue2 轮播图slide组件实例代码
2018/05/31 Javascript
详解Vue改变数组中对象的属性不重新渲染View的解决方案
2018/09/21 Javascript
在Vue中使用CSS3实现内容无缝滚动的示例代码
2020/11/27 Vue.js
python通过shutil实现快速文件复制的方法
2015/03/14 Python
Python实现网站注册验证码生成类
2017/06/08 Python
对Python中gensim库word2vec的使用详解
2018/05/08 Python
Python使用matplotlib实现基础绘图功能示例
2018/07/03 Python
python实现弹跳小球
2019/05/13 Python
python开发之anaconda以及win7下安装gensim的方法
2019/07/05 Python
python opencv 简单阈值算法的实现
2019/08/04 Python
Python浮点型(float)运算结果不正确的解决方案
2020/09/22 Python
Python Charles抓包配置实现流程图解
2020/09/29 Python
python自动化测试三部曲之unittest框架的实现
2020/10/07 Python
亚瑟士美国官网:ASICS美国
2017/02/01 全球购物
Spartoo美国:欧洲排名第一的在线时装零售商
2019/12/12 全球购物
药剂专业自荐信范文
2014/04/16 职场文书
三方协议书范本
2014/04/22 职场文书
商务日语专业的自荐信
2014/05/23 职场文书
2014年德育工作总结
2014/11/20 职场文书
个人自荐书怎么写
2015/03/26 职场文书
关于五一放假的通知
2015/08/18 职场文书
财务会计个人原因辞职信
2019/06/21 职场文书
评估“风险”创业计划的几大要点
2019/08/12 职场文书
如何使用Tkinter进行窗口的管理与设置
2021/06/30 Python
SQL Server数据库基本概念、组成、常用对象与约束
2022/03/20 SQL Server
SQL Server2019安装的详细步骤实战记录(亲测可用)
2022/06/10 SQL Server