在之前Q群ChatGPT机器人使用的依赖仓库中,作者更新了V2 Fast ChatGPT API
的用法(截至此时该方法已失效),里面涉及到了协程的相关用法。协程在平时用到的不多,正好趁机补充补充知识。
协程(coroutine)又称微线程,是一中轻量级的线程,它可以在函数的特定位置暂停或恢复,同时调用者可以从协程中获取状态或将状态传递给协程。进程和线程都是通过CPU的调度实现不同任务的有序执行,而协程是由用户程序自己控制调度的,也没有线程切换的开销,所以执行效率极高[1]。
协程主要具有以下优势[2]:
1.协程极高的执行效率。因为子程序切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销,和多线程比,线程数量越多,协程的性能优势就越明显。
2.就是不需要多线程的锁机制,因为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断状态就好了,所以执行效率比多线程高很多。
3.把一个IO操作 写成一个协程。当触发IO操作的时候就自动让出CPU给其他协程。要知道协程的切换很轻的。 协程通过这种对异步IO的封装 既保留了性能也保证了代码的容易编写和可读性
协程的适用场景:
协程适用于I/O密集型而非计算密集型场景。在协程发起I/O请求后返回结果前往往有大量闲置时间——该时间可能用于网络数据传输、获取协议头、服务器查询数据库等,而I/O请求本身并不耗时,因此协程可以发送一个请求后让渡给系统干别的事,这就是协程提高性能的原因[3]。
utine
替换为async
,把yield from
替换为awaits
下面就用Python3.8来进行学习。
async
关键字定义了一个协程函数。
协程函数和普通的函数不一样,不能直接执行。必须将协程对象放入事件循环中来执行。
下面是一个示例:
import asyncioasync def fun():print(1)xc = fun() # 生成一个协程对象# 执行协程函数,必须将协程对象放入事件循环之中。
# Python3.7之前运行协程的方式
# loop = _event_loop() # 获取一个事件循环
# loop.run_until_complete(xc) # 将协程对象放入任务列表# Python3.7之后,可以使用下面的方式运行协程函数。
asyncio.run(xc)
await
作用是等待可等待对象。
可等待对象包含协程对象,future对象,task对象,示例:
import asyncioasync def func1():print("start")await func2()print("end")async def func2():i = 0while True:if i < 10:print(i)i += 1else:breakasyncio.run(func1())
这里的func1执行中途等待func2执行完毕再输出end,因此执行结果为:
start
0
1
2
3
4
end
在上面的示例中,func1一直等待func2执行结束再运行。如果需要不等待继续执行,可以将两个协程一起封装成一个task对象。
示例:
import asyncioasync def func1():print("start")await asyncio.sleep(1) # 注意,这里不在是等待func2对象,而是睡眠1sprint("end")async def func2():i = 0while True:if i < 5:print(i)await asyncio.sleep(1)i += 1else:breaktask_list = [func1(), func2()] # 构造一个任务列表
t1 = asyncio.wait(task_list) # 构造成为task对象
asyncio.run(t1) # 执行
输出:
start
0
end
1
2
3
4
注:这里两个函数是交替执行的,func1先输出start,遇到await
,切换成func2,再遇到await
,切换回func1。
在python3.7之后,可以使用
import asyncioasync def func1():print("start")await asyncio.sleep(1) # 注意,这里不在是等待func2对象,而是睡眠1sprint("end")async def func2():i = 0while True:if i < 5:print(i)await asyncio.sleep(1)i += 1else:breakasync def main():# 将协程封装到一个Task对象中并立即添加到事件循环的任务列表中,等待事件循环去执行(默认是就绪状态)。c1 = ate_task(func1(), name='c1')c2 = ate_task(func2(), name='c2')# 当执行某协程遇到IO操作时,会自动化切换执行其他任务。# 此处的await是等待相对应的协程全都执行完毕并获取结果,主要是为了方便观察。await c1 # 等待task对象await c2asyncio.run(main())
获取协程返回值至少有4种方式[5],这里学习一种,下面是示例:
import asyncioasync def func1(input1):return str(input1) + "output1"if __name__ == '__main__':loop = _event_loop()task = ate_task(func1("abc"))loop.run_until_complete(task)output = sult()print(output)
[1] Python协程讲解
[2] Python教程:协程
[3] Python 进程、线程、协程傻傻分不清楚?详细总结(附代码)
[4] Python协程
[5] Python:获取协程返回值的四种方式
本文发布于:2024-01-28 17:39:07,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/17064347519114.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |