协程及运用

协程

  • 使用
    • 方法一
    • 方法二
    • 网页下载中使用
    • 有返回值
  • 实战
    • 图片实战

一个线程多个任务,线程由操作系统开启,比较耗资源。线程内合理分配任务,充分利用线程内的资源,一个任务io阻塞时,cpu处理其他非阻塞任务。

使用

方法一

import asyncio
# 函数前加async后,成为协程对象
async def as_func():
    print('协程基本使用')
if __name__ == '__main__':
    # 1 创建一个协程对象
    async_obj = as_func()
    print(async_obj)
    # 2 创建事件循环
    event_loop = asyncio.get_event_loop()
    # 3 执行协程对象
    event_loop.run_until_complete(async_obj)

方法二

  • 可能报RuntimeError: Event loop is closed
import asyncio
# 函数前加async后,成为协程对象
async def as_func():
    print('协程基本使用')
if __name__ == '__main__':
    # 1 创建一个协程对象
    async_obj = as_func()
    print(async_obj)
    # 2 执行协程
    asyncio.run(async_obj)
    

网页下载中使用

import asyncio
# 函数前加async后,成为协程对象
async def as_download(url, t):
    print(url + '协程下载')
    await asyncio.sleep(t)
    print(url + '下载完成')

async def main():
    urls = [
        'url1',
        'url2',
        'url3',
        'url4',
    ]
    as_tasks = []
    for url in urls:
        as_task = asyncio.create_task(as_download(url, 2))
        as_tasks.append(as_task)
    await asyncio.wait(as_tasks)

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

有返回值

  • wait和gather
import asyncio
async def as_download1():
    print("协程1开始")
    await asyncio.sleep(1)
    print("协程1完成")
    return "协程1返回"
async def as_download2():
    print("协程2开始")
    await asyncio.sleep(2)
    print("协程2完成")
    return "协程2返回"
async def as_download3():
    print("协程3开始")
    await asyncio.sleep(3)
    print("协程3完成")
    return "协程3返回"
async def main():
    tasks = [
        asyncio.create_task(as_download3()),
        asyncio.create_task(as_download1()),
        asyncio.create_task(as_download2()),
    ]
    # 取返回值一, wait, 返回的结果是set集合,无序
    result, pending = await asyncio.wait(tasks)
    for res in result:
        print(res.result())
    print("--以上是随机顺序--"*3)
    print("--以下是与任务相同顺序--"*3)
    # 取返回值二, gather, 同map一样,返回的结果的顺序与任务顺序一致
    # return_exceptions=True,即使有错误,任务正常执行,返回错误信息
    # return_exceptions=False,如果有错误,程序报错,任务停止
    result = await asyncio.gather(*tasks, return_exceptions=True)
    for res in result:
        print(res)
if __name__ == '__main__':
    asyncio.run(main())

实战

  • aiohttp和aiofiles安装
pip install aiohttp
pip install aiofiles

图片实战

链接: url_list
链接: url_list
链接: url_list

import aiohttp
import asyncio
import aiofiles
async def pic_download(url):
    try:
        name = url.split("/")[-1]
        # 创建session对象 with使用完后自行关闭
        async with aiohttp.ClientSession() as session:
            # 发送请求url请求
            async with session.get(url) as resp:
                # content.read()读取图片数据
                # resp.text()读取源代码即可
                content = await resp.content.read()
                # 写入文件会阻塞, 用aiofiles提升效率
                async with aiofiles.open(name, mode="wb") as f:
                    await f.write(content)
                    return "finish complete"
    except:
        print('报错')
        return "failure"
async def main():
    url_list = [
        "",
        "",
        "",
        "",
        "",
    ]
    tasks = []
    for url in url_list:
        # 创建任务
        task = asyncio.create_task(pic_download(url))
        tasks.append(task)
    await asyncio.wait(tasks)
if __name__ == '__main__':
    # asyncio.run(main()) 此句与下2句等同,但在一些版本中报错
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())

你可能感兴趣的:(spider,协程及运用,python)