python 协程 & 异步编程(asyncio)

2022-08-30 13:06:44

协程

协程(Coroutine),也可以被称为微线程,是一种用户态内的上下文切换技术。简而言之,其实就是通过一个线程实现代码块相互切换执行
协程意义:在一个线程中如果遇到IO等待时间,线程不会傻傻等,利用空闲的时候再去干点其他事。

一、效果演示

1.1 正常执行

from timeimport sleepfrom timeimport time
start= time()deffunc1():print(1)
    sleep(1)print(2)deffunc2():print(3)
    sleep(1)print(4)
func1()
func2()
end= time()# 输出1234print(end-start)# 2.028127908706665

1.2 使用asynico

import asynciofrom timeimport time

start= time()asyncdeffunc1():print(1)await asyncio.sleep(1)print(2)asyncdeffunc2():print(3)await asyncio.sleep(1)print(4)

tasks=[
    func1(),
    func2()]
loop= asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
end= time()# 输出 1324print(end-start)# 1.010634422302246

可以很明显的看到程序在遇到i0费时操作时,asyncio的效率有多高

学习使用

3.1 事件循环

事件循环就是把你创建好的函数,加入到任务列表,事件循环负责监听任务列表,当执行这个函数遇到费时操作时,事件循环就会控制跳到其他可执行的任务,当没有可执行的任务就会等待当前任务执行完毕,只有全部任务都执行完毕,才会退出循环。

# 伪代码

任务列表=[ 任务1, 任务2, 任务3,...]whileTrue:
    可执行的任务列表,已完成的任务列表= 去任务列表中检查所有的任务,将'可执行''已完成'的任务返回for 就绪任务in 可执行的任务列表:
        执行已就绪的任务for 已完成的任务in 已完成的任务列表:
        在任务列表中移除 已完成的任务

	如果 任务列表 中的任务都已完成,则终止循环
import asyncio# 去生成或获取一个事件循环
loop= asyncio.get_event_loop()# 将任务放到`任务列表`
loop.run_until_complete(任务)

asyncio.wait()

控制任务
通过asyncio.wait()可以控制多任务

asyncio.wait()是一个协程,不会阻塞,立即返回,返回的是协程对象。传入的参数是future或协程构成的可迭代对象。最后将返回值传给run_until_complete()加入事件循环

3.2 携程函数

协程函数,定义函数的时候使用async def 函数名
协程对象,执行写成函数()得到的学成对象

# d定义协程函数asyncdeffunc():pass# 获取写成对象
result= func()print(result)# <coroutine object func at 0x000002326168AD40>

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

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

import asyncioasyncdeffunc():print("执行协程函数!")

result= func()

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

python3.7有个更简便的方法

import asyncioasyncdeffunc():print("执行协程函数!")

result= func()# loop = asyncio.get_event_loop()# loop.run_until_complete( result )
asyncio.run(result)# python3.7

3.3 await

await + 可等待的对象(协程对象、Future、Task对象 -> IO等待)
示例一

import asyncioasyncdeffunc():print("开始")
    response=await asyncio.sleep(2)print("结束",response)

asyncio.run( func())

示例二:

import asyncioasyncdefothers():print("start")await asyncio.sleep(2)print('end')return'返回值'asyncdeffunc():print("执行协程函数内部代码")# 遇到IO操作挂起当前协程(任务),等IO操作完成之后再继续往下执行。当前协程挂起时,事件循环可以去执行其他协程(任务)。
    response=await others()print("IO请求结束,结果为:", response)asyncdeffunc1():print('func1')
tasks=[
    func(),
    func1()]
asyncio.run(asyncio.wait(tasks))

3.4 Task对象

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

注意:asyncio.create_task() 函数在 Python 3.7 中被加入。在 Python 3.7 之前,可以改用低层级的asyncio.ensure_future() 函数。
示例一:

import asyncioasyncdeffunc():print(1)await asyncio.sleep(2)print(2)return"返回值"asyncdefmain():print("main开始")# 创建Task对象,将当前执行func函数任务添加到事件循环。
    task1= asyncio.create_task( func())# 创建Task对象,将当前执行func函数任务添加到事件循环。
    task2= asyncio.create_task( func())print("main结束")# 当执行某协程遇到IO操作时,会自动化切换执行其他任务。# 此处的await是等待相对应的协程全都执行完毕并获取结果
    ret1=await task1
    ret2=await task2print(ret1, ret2)


asyncio.run( main())

示例二:

import asyncioasyncdeffunc():print(1)await asyncio.sleep(2)print(2)return"返回值"asyncdefmain():print("main开始")# name给任务起个名字
    task_list=[
        asyncio.create_task(func(), name='n1'),
        asyncio.create_task(func(), name='n2')]print("main结束")# done是任务列表返回的集合,pending未完成任务的集合
    done, pending=await asyncio.wait(task_list, timeout=None)print(done)# {<Task finished name='n1' coro=<func() done, defined at C:/Users/86166/Deskto/a.py:4> result='返回值'>, <Task finished name='n2' coro=<func() done, defined at C:/Users/86166/Desktop/a.py:4> result='返回值'>}

asyncio.run(main())

示例三:

import asyncioasyncdeffunc():print(1)await asyncio.sleep(2)print(2)return"返回值"


task_list=[
    func(),
	func(),]

done,pending= asyncio.run( asyncio.wait(task_list))print(done)
  • 作者:上升的蜗牛
  • 原文链接:https://blog.csdn.net/qq_51014805/article/details/122152645
    更新时间:2022-08-30 13:06:44