python 异步编程(一)协程

概念

  • 协程,也可以称作微线程,是一种用户态内的上下文切换技术。简而言之,其实就是通过一个线程实现代码块互相切换
  • 协程不是计算机提供,是程序员认为创造的
  • 在一个线程中,如果遇到耗时 IO ,使线程利用等待时间干点别的事

实现

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
    gr1. switch()  # 第5步:功换到 func1 函数,从上一次执行的位置继续向后执行
    print(4)  # 第8步:输出 4


if __name__ == '__main__':
    gr1 = greenlet(func1)
    gr2 = greenlet(func2)
    gr1.switch()  # 第1步:去执行 func1 函数


yield

生成器关键字来实现协程(伪协程)

def func1():
    yield 1
    yield from func2()
    yield 2


def func2():
    yield 3
    yield 4


if __name__ == '__main__':
    for i in func1():
        print(i)

asyncio

python 3.4 及更高版本可用

import asyncio


@asyncio.coroutines
def func1():
    print(1)
    yield from asyncio.sleep(2)  # 固定写法,执行到该语句时,阻塞2秒去执行其它协程函数
    print(2)


@asyncio.coroutines
def func2():
    print(3)
    yield from asyncio.sleep(2)
    print(4)


if __name__ == '__main__':
    # 以下为固定写法
    tasks = [
        asyncio.ensure_future( func1() ),
        asyncio.ensure_future( func2() )
    ]
    loop = asyncio.get_event_loop()
    loop.run_until_complete( asyncio.wait(tasks) )

async & await

python 3.5 及更高版本可用 ,是目前最的主流方式

import asyncio


async def func1():
    print(1)
    await asyncio.sleep(2)  # 固定写法,执行到该语句时,阻塞2秒去执行其它协程函数
    print(2)


async def func2():
    print(3)
    await asyncio.sleep(2)
    print(4)


if __name__ == '__main__':
    # 以下为固定写法
    tasks = [
        asyncio.ensure_future( func1() ),
        asyncio.ensure_future( func2() )
    ]
    loop = asyncio.get_event_loop()
    loop.run_until_complete( asyncio.wait(tasks) )

案例:下载图片

普通写法

import requests


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


if __name__ == '__main__':
    url_list = [
        "https://th.wallhaven.cc/small/pk/pkw6y3.jpg",
        "https://th.wallhaven.cc/lg/dp/dpo38l.jpg",
        "https://th.wallhaven.cc/small/8o/8oky1j.jpg"
    ]
    for item in url_list:
        download_image(item)


协程写法(异步)

requests库是一个同步请求库,使用异步请求可使用aiohttp库

import asyncio
import aiohttp


async def download_image(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('images/' + file_name, mode='wb') as file_object:
            file_object.write(content)
        print('下载完成' + url)


async def main():
    async with aiohttp.ClientSession() as session:
        url_list = [
            "https://th.wallhaven.cc/small/pk/pkw6y3.jpg",
            "https://th.wallhaven.cc/lg/dp/dpo38l.jpg",
            "https://th.wallhaven.cc/small/8o/8oky1j.jpg"
        ]
        tasks = [asyncio.create_task(download_image(session, url)) for url in url_list]
        await asyncio.wait(tasks)


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

posted @ 2021-09-30 11:26  寡淡的白开水  阅读(289)  评论(0)    收藏  举报