Python协程

centuryw2个月前 (08-06)Python83

协程

协程也称为微线程,就是通过一个线程实现代码块相互切换执行。

实现方式

  • greenlet(早期模块)

  • yield关键字

  • asyncio装饰器

  • async、await关键字【推荐】

1. greenlet实现协程   

安装模块

pip install greenlet

示例代码

from greenlet import greenlet


def task1():
    print(1)  # 1. 输出1
    gr2.switch()  # 切换到gr2
    print(2)  # 3. 输出2
    gr2.switch()  # 切换到gr2


def task2():
    print(3)  # 2. 输出3
    gr1.switch()  # 切换到gr1
    print(4)  # 4. 输出4


gr1 = greenlet(task1)
gr2 = greenlet(task2)
gr1.switch()  # 执行task1函数

执行结果

1
3
2
4
进程已结束,退出代码0

2. yield关键字实现协程   

注:函数内如果含有yield代表此函数是个生成器函数

示例代码

def task1():
    yield 1
    yield from task2()  # 跳转到task2函数
    yield 2


def task2():
    yield 3
    yield 4


t1 = task1() 
for item in t1:
    print(item)

执行结果

1
3
2
4
进程已结束,退出代码0

3. asyncio实现协程

注:在python3.4之后可用

特点:遇到io阻塞自动切换

示例代码

import asyncio


@asyncio.coroutine
def task1():
    print(1)
    yield from asyncio.sleep(2)  # 模拟耗时操作, 自动切换到tasks中的其他任务
    print(2)


@asyncio.coroutine
def task2():
    print(3)
    yield from asyncio.sleep(2)  # 模拟耗时操作, 自动切换到tasks中的其他任务
    print(4)


tasks = [
    asyncio.ensure_future(task1()),
    asyncio.ensure_future(task2()),
]
# 生成或获取一个事件循环
loop = asyncio.get_event_loop()
# 将任务放到'任务列表'
loop.run_until_complete(asyncio.wait(tasks))

执行结果

1
3
2
4
进程已结束,退出代码0

3. async&await关键字实现协程

注:在python3.5之后可用

注:与asyncio的实现区别在于使用async代替了装饰器

示例代码

import asyncio


async def task1():
    print(1)
    await asyncio.sleep(2)  # 模拟耗时操作, 自动切换到tasks中的其他任务
    print(2)


async def task2():
    print(3)
    await asyncio.sleep(2)  # 模拟耗时操作, 自动切换到tasks中的其他任务
    print(4)


tasks = [
    asyncio.ensure_future(task1()),
    asyncio.ensure_future(task2()),
]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))

执行结果

1
3
2
4
进程已结束,退出代码0

4. 下载图片案例使用协程与不使用协程的对比

不使用协程(同步)

代码
import requests
import time


def download_img(img_url):
    print('开始下载:', img_url)
    resp = requests.get(img_url)
    print('下载完成:', img_url)
    file_name = img_url.split('/')[-1]  # 提取图片名称
    # 保存图片
    with open(file_name, 'wb') as f:
        f.write(resp.content)


if __name__ == '__main__':
    # 要下载的图片url列表
    url_list = [
        'http://img2.woyaogexing.com/2017/12/06/6f1480322fb2d1f5!600x600.jpg',
        'http://img2.woyaogexing.com/2017/12/06/b9b8d610495a3a9c!600x600.jpg',
        'http://img2.woyaogexing.com/2017/12/06/3442cb320452f9d5!600x600.jpg'
    ]
    # 统计时间
    start_time = time.time()
    # 遍历列表进行下载
    for url in url_list:
        download_img(url)
    end_time = time.time()
    print('总共耗时:{}'.format(round((end_time - start_time) * 1000)) + 'ms')
执行结果
开始下载: http://img2.woyaogexing.com/2017/12/06/6f1480322fb2d1f5!600x600.jpg
下载完成: http://img2.woyaogexing.com/2017/12/06/6f1480322fb2d1f5!600x600.jpg
开始下载: http://img2.woyaogexing.com/2017/12/06/b9b8d610495a3a9c!600x600.jpg
下载完成: http://img2.woyaogexing.com/2017/12/06/b9b8d610495a3a9c!600x600.jpg
开始下载: http://img2.woyaogexing.com/2017/12/06/3442cb320452f9d5!600x600.jpg
下载完成: http://img2.woyaogexing.com/2017/12/06/3442cb320452f9d5!600x600.jpg
总共耗时:179ms

使用协程(异步)

代码
import time

import aiohttp
import asyncio


async def fetch(session, url):
    print('发送请求: {}'.format(url))
    async with session.get(url) as response:
        content = await response.content.read()
        file_name = url.split('/')[-1]  # 提取图片名称
        # 保存图片
        with open(file_name, 'wb') as f:
            f.write(content)
        print('下载完成: {}'.format(url))


async def main():
    async with aiohttp.ClientSession() as session:
        url_list = [
            'http://img2.woyaogexing.com/2017/12/06/6f1480322fb2d1f5!600x600.jpg',
            'http://img2.woyaogexing.com/2017/12/06/b9b8d610495a3a9c!600x600.jpg',
            'http://img2.woyaogexing.com/2017/12/06/3442cb320452f9d5!600x600.jpg'
        ]
        tasks = [asyncio.create_task(fetch(session, url)) for url in url_list]
        await asyncio.wait(tasks)
执行结果
发送请求: http://img2.woyaogexing.com/2017/12/06/6f1480322fb2d1f5!600x600.jpg
发送请求: http://img2.woyaogexing.com/2017/12/06/b9b8d610495a3a9c!600x600.jpg
发送请求: http://img2.woyaogexing.com/2017/12/06/3442cb320452f9d5!600x600.jpg
下载完成: http://img2.woyaogexing.com/2017/12/06/6f1480322fb2d1f5!600x600.jpg
下载完成: http://img2.woyaogexing.com/2017/12/06/b9b8d610495a3a9c!600x600.jpg
下载完成: http://img2.woyaogexing.com/2017/12/06/3442cb320452f9d5!600x600.jpg
总共耗时:45ms


    相关文章

    Pandas笔记

    Pandas笔记

    官方文档 序列与数据框的构造 构造序列 方法: 通过同质的列表或元组创建通过字典构建通过Numpy中的一维数组构建通过数据框DataFrame中的某一列构...

    virtualenv虚拟环境的使用

    廖雪峰教程 安装pip install virtualenv创建虚拟环境mkvirtualenv 环境名称删除虚拟环境rmvirtualenv激活环境Linux下 source 环境bin...

    OS模块使用

    菜鸟教程...

    分布式爬虫

    分布式爬虫

    单机爬虫架构 分布式爬虫架构 Redis队列 Redis,非关系型数据库,key-value形式存储,结构灵活。 是内存中的数据结构存储系统,处理速度快性能...

    Python读取csv文件并保存到mysql数据库

    Python读取csv文件并保存到mysql数据库

    测试数据 部分数据 airports下载 方法一:使用pymysql库 需要先在mysql内建好数据表(此处使用下图) import pymysql def...

    matplotlib索引

    matplotlib索引

    原文链接:https://matplotlib.org/ Matplotlib是一个Python 2D 绘制库它以各种硬拷贝格式和跨平台的交互环境生成出版物质量数据。 Matplotlib...

    发表评论

    访客

    看不清,换一张

    ◎欢迎参与讨论,请在这里发表您的看法和观点。