python协程学习

一、什么是协程及实现方式

1.1 协程

        又称微线程,纤程,也称为用户级线程,在不开辟线程的基础上完成多任务,也就是在单线程的情况下完成多任务,多个任务按照一定顺序交替执行。

1.2 实现方式

  1. greenlet,早期模块;
  2. yield关键字;
  3. asyncio装饰器 (py3.4);
  4. async、await关键字 (py3.5)(推荐);

二、实现方式示例

2.1 greenlet

from greenlet import greenlet
def func1():
    print(1)        # 第1步: 输出 1
    gr2.switch()    # 第3步: 切换到 func2 函数
    print(2)        # 第6步: 输出 2
    gr2.switch()    # 第7步: 切换到 func2 函数,从上一次执行的位置继续向后执行

def func2() :
    print(3)        # 第4步: 输出 3
    grl.switch()    # 第5步: 切换到 func1 函数,从上一次执行的位置继续向后执行
    print(4)        # 第8步: 输出 4

gr1 = greenTet(func1)
gr2 = greenTet(func2)

grl.switch()        # 第1步: 去执行 func1 函数

2.2 yield关键字

import time

def work1():
    while True:
        print("----work1---")
        yield
        time.sleep(0.5)

def work2():
    while True:
        print("----work2---")
        yield
        time.sleep(0.5)

def main():
    w1 = work1()
    w2 = work2()
    while True:
        next(w1)
        next(w2)

if __name__ == "__main__":
    main()

2.3 asyncio装饰器(py3.4)

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

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

tasks = [
    asyncio.ensure_future( func1()),
    asyncio.ensure_future( func2())
]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))

2.4 async、await关键字 (py3.5)

import asyncio

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

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

tasks = [
    asyncio.ensure_future( func1()),
    asyncio.ensure_future( func2())
]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))

三、协程的意义

        在一个线程中如果遇到IO等待时间(比如本地磁盘数据读取,及网络数据请求),线程不会干等,利用空闲的时间再去干其他事。

        案例:去下载三张图片(网络IO)

普通方式(也就是同步编程):

import requests

def download_image(url):
    print("开始下载:", url)  #发送网络请求,下载图片
    response = requests.get(url)
    print("下载完成")
    # 图片保存到本地文件
    file_name = url.rsplit('_')[-1]
    with open(file_name, mode='wb') as file_object:
        file_object.write(response.content)


if __name__ == "_main__":
    url_list = [
    "https://www3.autoimg.cn/newsdfs/g26/M02/35/A9/120x90_0_autohomecar_ChsEe12AX06A0OH_AAFocMs8nzu621.jpg",
    "https://www2.autoimg.cn/newsdfs/g30/M01/3C/E2/120x90_0_autohomecar_chcCSV2BBICAUntfAADjJFd6800429.jpg",
    "https://www3.autoimg.cn/newsdfs/g26/M0B/3C/65/120x90_0_autohomecar_ChcCP12BFCmAIO83AAGq7vK0sGY193.jpg"
    ]
    for item in url_list:
        download_image(item)

协程方案(也就是异步编程):

import aiohttp
import asyncio

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]
        with open(file_name, mode="wb") as file_object:
            file_object.write(content)

async def main():
    async with aiohttp.ClientSession() as session:
        url_list =["https://ww3.autoimg.cn/newsdfs/g26/M02/35/A9/120x90_0_autohomecar_ChsEe2AX06A00H_AAFOCHs8nzU621.jpg",
                   "https://ww2.autoimg.cn/newsdfs/g30/M01/3C/E2/120x90_0_autohomecar_ChcCSV288ICAUntfAADjJFd6800429.jpg",
                   "https://wm3.automg,cn/newsdfs/g26/M0B/3C/65/120x90_0_autohomecar_ChcCP12BFCmA083AAGq7VK0sGY193.jpg"
        ]
        tasks = [asyncio.create_task(fetch(session, url)) for url in url_list]
        await asyncio.wait(tasks)

if __name__ == "__main__":
    asyncio.run(main())

四、快速上手

4.1 基本语法       

        协程函数,定义函数时候用async修饰,如下

async def func():
    pass
result = func()  # 获取协程对象

        注意,执行协程函数创建协程对象,函数内部代码不会执行;如果想要运行协程函数内部代码,必须要讲协程对象交给事件循环来处理。如下

import asyncio

async def func():
    print("快来搞我吧!")

result = func()

# ss1oop = asyncio.get_event_loop()
# ss1oop.run_until_complete( result )

asyncio.run( result ) # python3.7

4.2 await

 示例一:

        await + 可等待的对象(协程对象,Future,Task对象)

import asyncio

async def func():
    print("快来搞我吧!")
    response = await asyncio.sleep(2)
    print("结束", response)

result = func()

ss1oop = asyncio.get_event_loop()
ss1oop.run_until_complete( result )

#asyncio.run( result ) # python3.7

 

4.3 Task对象

        在事件中循环中添加多个任务。

        Tasks用于并发调度协程,通过asyncio.create_task(协程对象)的方式创建Task对象,这样可以让协程加入事件循环中等待被调度执行。除了使用 asyncio.create_task(函数以外,还可以用低层级的loop.create_task0或 ensure_future()函数。不建议手动实例化 Task 对象。
        注意:asyncio.create_task() 函数在 Python 3.7 中被加入。在 Python 3.7 之前,可以改用低层级的asyncio.ensure_future()函数。

示例一:

 实例2:

 4.4 asyncio.Future对象

        Task继承Future,Task对象内部await结果的处理基于Future对象来的。

示例一:

示例二:

 4.5 concurrent.futures.Future对象

        使用线程池、进程池实现异步操作时用到的对象。

猜你喜欢

转载自blog.csdn.net/qq_31112205/article/details/130015052
今日推荐