Python协程

centuryw1年前 (2022-08-06)Python467

协程

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

实现方式

  • 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


    相关文章

    re正则表达式的使用

    官方文档 菜鸟教程 使用注意点 re.findall("a(.*?)b","str") 能够返回括号中的内容。括号前后内容起到定位和过滤的效果原始字符串 r...

    Scrapy框架使用

    Scrapy框架使用

    Scrapy中文手册 scrapy爬虫流程及各个部件作用 Scrapy入门 1.创建一个scrapy项目 scrapy startproject mySp...

    requirements文件的使用

      作用:记录所有包以及精确的版本号,以便在新环境下进行部署操作 使用示例: 目前需要把环境A的所有包安装到环境B 在环境A内执行 pip freez...

    time库的使用

    time库的使用

    time库是Python提供的处理时间的标准库。time库提供系统级精确计时器的计时功能,可以用来分析程序性能,也可以让程序暂停运行时间。 time库概述 t...

    PyInstaller库(打包)的使用

    PyInstaller库(打包)的使用

    PyInstaller能够在多个操作系统下将Python源文件打包变成可运行的可执行文件。 安装 pip install PyInstaller 常用参...

    Scikit-learn库(机器学习工具)

    介绍 Python语言的机器学习工具Scikit-learn包括许多知名的机器学习算法的实现Scikit-learn文档完善,容易上手,丰富的API,使其在学术界颇受欢迎...

    发表评论

    访客

    看不清,换一张

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