协程学习心得

在一个线程中如果遇到IO等待事件,线程不会傻傻等,利用空余时间去做其他事情

事件循环

任务列表 = 【 任务1, 任务2, 任务3, 。。。】

while True:

        可执行的任务列表,已完成的任务列表 = 去任务列表中检查所有的任务,将“可执行”,“已完成”的任务返回

        for 就绪任务 in 可执行的任务列表:

                执行已就绪的任务

        for 已完成的任务 in 已完成的任务列表

                在任务列表中移除 已完成的任务

        如果 任务列表 中的任务全部都已完成,则终止循环.

import asyncio
# 去生成一获取一个事件循环
loop = asyncio.get_event_loop()
# 将任务放到“任务列表”
loop.run_until_complete(任务)

 快速上手

协程函数,定义函数的时候aysnc def 函数名

协程对象,执行携程函数()得到的协程对象

# 协程函数
async def func()
    pass


# 协程对象
result = func()

注意:执行协程函数创建协程对象,函数内部代码不会执行

如果想要执行携程函数内部代码,必须要将协程对象交给事件循环来处理

完整代码如下:

python3.7之前

import asyncio

async def fun():
    print("hello world")


result = fun()
loop = asyncio.get_event_loop()
loop.run_until_complete(result)

python3.7之后

import asyncio

async def fun():
    print("hellow world")


result = fun()
asynicio.run(result)

await

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

import asyncio

async def fun():
    print("hello world")
    response = await asyncio.sleep(2)
    print("结果", response)

asyncio.run(fun())
import asyncio

async def others():
    print("Start")
    await asyncio.sleep(2)
    print("End")
    return "返回值"

async def func():
    print("执行携程函数内部代码")
    # 遇到IO操作挂起当前协程(任务),等IO操作完成之后再继续往下执行,当协程挂起时,事件循环可以去
      执行其他协程(任务)
    response = others()
    print("IO请求结束,结果为", response)



asyncio.run(func())
import asyncio

async def others():
    print("Start")
    await asyncio.sleep(2)
    print("End")
    return "返回值"

async def func():
    print("执行携程函数内部代码")
    # 遇到IO操作挂起当前协程(任务),等IO操作完成之后再继续往下执行,当协程挂起时,事件循环可以去
      执行其他协程(任务)
    response1 = others()
    print("IO请求结束,结果为", response2)    
    response3 = others()
    print("IO请求结束,结果为", response3)



asyncio.run(func())

await就是等待对象的值得到结果之后再继续往下走

 Task对象

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

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

注意:asyncio.create_ftask()函数在python3.7中被加入,在python3.7之前,可以改用低层级的asyncio.ensure_future()函数

import asyncio

async def func():
    print(1)
    await asyncio.sleep(2)
    print(2)
    return "返回值"


async def main():
    task1 = asyncio.create_task(func())
    task2 = asyncio.create_task(func())
    print("main结束")

    # 当执行某协程遇到IO操作时,会自动化切换执行其他任务
    # 此处的await是等待相对应的协程全部执行完毕并获取结果
    ret1 = await task1
    ret2 = await task2
    print(ret1, ret2)

asyncio.run(main())

常用写法

import asyncio

async def func():
    print(1)
    await asyncio.sleep(2)
    print(2)
    return "返回值"


async def main():
    print("main开始")
    task_list = [
                    asyncio.create_task(func(), name="n1"),
                    asyncio.create_task(func(), name="n2")
                ]
    print("main结束")

    done, pending = await asyncio.wait(task_list, timeout=None)
    print(done)

asyncio.run(main())

不常用写法

import asyncio

async def func():
    print(1)
    await asyncio.sleep(2)
    print(2)
    return "返回值"


task_list = [
             func(),
             func()
              ]
done, pending = asyncio.run(asyncio.wait(task_list))
print(done)

asyncio.Future对象

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

async def main():
    # 获取当前事件循环
    loop = asyncio.get_running_loop()
    # 创建一个任务(Future对象),这个任务什么都不干
    fut = loop.create_future()
    # 等待任务最终结果(Future对象),没有结果会一直等下去
    await fut

asyncio.run(main())

解释Task的过程

import asyncio

async def set_after(fut):
    await asyncio.sleep(2)
    fut.set_result("666")


async def main():
    # 创建当前事件循环
    loop = asyncio.get_running_loop()
    # 创建一个任务(Future对象),没绑定任何行为,则这个任务永远不知道什么时候结束
    fut = loop.create_future()
    # 创建一个任务(Task对象),绑定了set_after函数,函数内部在2s之后,会给fut赋值
    # 即手动设置future任务的最终结果,那么fut就可以结束了
    await loop.create_task( set_after() )
    # 等待Future对象获取最终结果,否则一致等下去
    data = await fut
    print(data)


asyncio.run( main() )

区别于concurrent.futures.Future对象

import time

from concurrent.futures import Future

from concurret.futures.thread import ThreadPoolExecutor

from concurret.futures.process import ProcessPoolExecutor

def func(value):

        time.sleep(1)

        print(value)

        return 123

# 创建线程池

pool = ThreadPoolExecutor(max_workers = 5)

# 创建进程池

# pool = ProcessPoolExecutor(max_workers = 5)

for i in range(10)

        fut = pool.submit(func, 1)

        print(fut)

爬虫案例

import asyncio

class AsynContextMannager:
    def __init__:
        self.conn = conn


    async def do_something(self):
        # 异步操作数据库
        return 666


    async def __aenter__(self):
        # 异步链接数据库
        self.conn = await asyncio.sleep(1)
        reeturn self

    
    async def __aexit(self, exc_type, exc, tb)
        #异步关闭数据库链接
        await asyncio.sleep(1)


async def func():
    async with AsynContextMannager() as f:
        result = await f.do_something()
        print(result)

asyncio.run( func() )

异步上下文管理器

此种对象通过定义_aenter_()和_aexit_()方法来对async with语句中的环境进行控制。

import asyncio
import requests

async def download_image(url):
    # 发送网路请求,下载图片(遇到网路下载图片的IO请求,自动化切换到其他任务)
    print("开始下载", url)
    loop = asyncio.get_event_loop()
    # requests模块不支持异步操作,所以就使用线程池来配合实现
    future = loop.run_in_executor(None, requests.get, url)
    response = await future
    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 = [1,2,3]
    tasks = [
              download_image(url) for url in url_list  
            ]
    loop = asyncio.get_event_loop()
    loop.run_until_complete(asyncio.wait(tasks))

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值