Python协程的第三方模块asyncio基础使用-----------学习笔记

        协程主要用于多任务开发,任务之间来回切换,把一个方法作为一个任务,这样刚好符合爬虫的需求,请求是一个任务,解析是一个任务,保存是一个任务。

 

在python中的标准库,就有这么一个模块,叫做asyncio,从这个名字我们就知道,异步的io,就是为了解决大量的io操作提高效率而开发的。

import asyncio

"""
协程是异步任务,
并发是指一次处理多件事情
并行是指一次多件事

这个包使用事件循环驱动的协程 实现并发
所以说这是一个协程概念的实现方法库,他的英文名字叫郁金香

异步操作前面就得加上async
"""


# 一个协程函数
async def fun():
    print("我是一个函数")
    return "fun()"


def fun1():
    return "fun1"


def run1(f):
    event_loop = asyncio.get_event_loop()
    # event_loop 执行协程对象,直到任务执行完毕
    event_loop.run_until_complete(f)
    print("简单封装")


if __name__ == "__main__":
    # 执行协程需要一个 event_loop对象
    f = fun()  # 协程对象
    print(f)  # <coroutine object fun at 0x0000020AE97D57C0>
    f1 = fun1()
    print(f1)  # fun1

    # 下面三个部分只能一个部分执行,三个部分执行会报错
    # --------------------------------------------------
    # 拿到事件循环对象
    # event_loop = asyncio.get_event_loop()
    # # # event_loop 执行协程对象,直到任务执行完毕
    # event_loop.run_until_complete(f)
    # # 关闭事件循环
    # event_loop.close()
    # ----------------------------------------------------
    # 简便写法,这个run方法里面就有上面两个操作
    # 这个run方法里面传递的是一个异步任务(协程对象),是对上面两个操作的封装
    asyncio.run(f)  # 我是一个函数
    # ----------------------------------------------------
    # 简单封装
    # run1(f)

        IO容易引起线程阻塞,为了解决阻塞搞出来的东西,不涉及到线程切换,cpu切换的是任务,所以切换的时间也给节省了,在一个线程里面,任务的来回切换,这个是有程序来控制切换,而线程是由操作系统来控制的,要比线程池高很多很多。

返回值处理

在多线程的使用中我们有时候也会需要使用返回值,asyncio模块同样也提供了返回值的处理方式

具体如下看代码

import asyncio


async def faker1():
    print("任务1开始")
    await asyncio.sleep(1)
    print("任务1完成")
    return "任务1结束"


async def faker2():
    print("任务2开始")
    await asyncio.sleep(2)
    print("任务2完成")
    return "任务2结束"


async def faker3():
    print("任务3开始")
    await asyncio.sleep(3)
    print("任务3完成")
    return "任务3结束"


async def main():
     # 生成任务列表
    tasks = [
        asyncio.create_task(faker3()),
        asyncio.create_task(faker1()),
        asyncio.create_task(faker2()),
    ]
    # 方案一, 用wait, 返回的结果在result中
    result, pending = await asyncio.wait(tasks)
    for r in result:
        print(r.result())
        
    # 方案二, 用gather, 返回的结果在result中, 结果会按照任务添加的顺序来返回数据
    # 	return_exceptions如果任务在执行过程中报错了. 返回错误信息. 
    result = await asyncio.gather(*tasks, return_exceptions=True)
    for r in result:
        print(r)


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

下面是一个下载图片的案例

原先的request模块和io操作都是同步的模块,所以我们需要异步的请求和异步的io操作,这里就有两个模块,aiofiles ,aiohttp

# aiohttp模块 aiofiles模块
import asyncio
import aiofiles
import aiohttp

"""
asyncio模块只支持tcp,udp协议
所以需要执行异步的http请求的话只能使用第三方http模块 aiohttp

打算交给asyncio处理的协程,需要使用asnyc装饰
"""
# 下载任务
async def download(url):
    print("开始下载:", url)
    file_name = '../data/img/' + url[29:35]
    # 相当于request,因为这个req模块是同步的不是异步的,所以需要aiohttp
    # async这个修饰表示这个代码里面的代码是异步的,可以等待
    async with aiohttp.ClientSession() as session:
        # 发送网络请求
        async with session.get(url) as resp:
            # await resp.text()
            content = await resp.content.read()  # =>resp.content()
            # 写文件,
            # 正因为下面有await这个修饰,所以这里需要这个async修饰才能当io时候交给主程序
            async with aiofiles.open(file_name + ".jpg", mode="wb") as f:
                # 阻塞的操作通过协程实现,通过await把职责交给协程,在流畅的python当中这里使用的是yield from
                # 这里f.write(content)会有io操作会阻塞,所以需要使用await,当发生io时候,把程序的控制权交给主程序,去执行其他代码
                # 等这里的io发送完毕后在回复这个协程
                await f.write(content)


    print("下载完毕:", url)


async def main():
    url_lit = [

        "https://img1.baidu.com/it/u=2813501359,388694820&fm=253&fmt=auto&app=138&f=JPEG?w=440&h=591",
        "https://img1.baidu.com/it/u=429699237,3830680416&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=718",
        "https://img0.baidu.com/it/u=3304588560,3276370823&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=677"
    ]
    # 任务列表
    tasks = []
    # 将每个url创建成一个任务,添加到tasks列表中
    # task对象用于驱动协程
    for url in url_lit:
        t = asyncio.create_task(download(url))
        tasks.append(t)
    # wait()里面需要的是task对象,wait方法是一个异步的不会阻塞的协程,协程函数,虽然函数的名称是await
    # 等待传递给他的所有协程执行完毕后结束,
    # 流畅的python书里面的原话是 ”asyncio.wait(...) 参数是由一个协程构造的可迭代对象,wait会把个协程封装成一个Task对象
    # “
    await asyncio.wait(tasks)


if __name__ == "__main__":
    # 简便写法,这个run方法里面就有上面两个操作
    # 这个run方法里面传递的是一个异步任务(协程对象)
    asyncio.run(main())

欢迎关注作者公众号

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值