Python并行编程实践(下)
00 分钟
2022-8-1
2024-6-4
type
status
date
slug
summary
tags
category
icon
password

协程与异步

这里主要使用的就是asyncio这个库,用来编写并发代码,使用 async/await 语法,至于协程和异步什么关系,可以参考官方文档的一段话:
协程是子例程的更一般形式。子例程可以在某一点进入并在另一点退出。 协程则可以在许多不同的点上进入、退出和恢复。 它们可通过 async def 语句来实现

运行程序

异步程序的运行在不同的 python 版本有不同的方法,如果你在网上看如下这种运行异步程序的方法:
上面写的也是没错的,但此方法是 python3.7 之前运行异步程序的方法,在 3.7 之后有了更简便的写法,如下:
也建议大家使用更高级的写法,因为谁不想少写点代码呢。

基本使用

在 python 中,如果想直接调用一个使用async装饰的异步函数,一点要在前面加await等待运行结束

创建任务

当你想创建一个后台任务,让它慢慢执行的时候,可以用这个:asyncio.create_task(coro, *, name=None)其中 name 形参是 3.8 加入进去的,意思是任务的名字,使用实例如下:
可以看到我们在开始就创建了一个后台任务task,该任务会在 3 秒后输出内容,随后又调用了三次函数factorial,该函数会等待 1 秒后返回,所以输出了以下内容,但如果你们尝试把函数factorial只运行 1 此或两次,会发现任务task没有执行完程序就结束了,因为我们只是把它当作一个后台任务来运行,并没有等待,这时有两种方案:
  • 如果你的程序的服务端程序就不用管了,反正不会结束
  • 如果你的代码就是一个脚本可以在最后等待后台任务的结束:

并发运行任务

看了上面你可能会说,我懂了,只要批量创建任务,它不就是并发了吗?也没错,但有更好的方法,就是使用asyncio.gather(*aws, return_exceptions=False),有两个参数,第一个参数就是一堆协程,第二个是发生异常时是直接中断还是随着结果一起返回,默认是中断不返回,这个函数有一个返回值,那就是所有任务的运行结果,如下示例:

控制速度

到现在为止,已经完成了使用异步的并发操作,但这种并发是不可控的,比如前文的线程池和进程池,都有一个参数为max_workers,是控制速度用的,而在异步编程中也有控制并发速度的,叫做信号量,简单写一个示例:
仔细观看输出的时候你会发现是5个5个一组的输出出来,这就是用到了信号量:asyncio.Semaphore(),他只有一个参数就是要限制的并发数量,然后把要限制的代码使用上下文管理器包裹起来就好,但要注意的是,实例化信号量的时候一定要在主事件循环中,也就是使用async装饰的函数里面才可以,否则会报错,大家可以尝试一下。

参考资料

结束了

其实标题上的“并行编程实践并不严谨”,因为线程池和异步的协程都是属于并发的,只有多进程的才是并行。然后呢,本篇文章也只是带大家入个门,知道咋用。至于为啥没写那么详细呢?我更希望看到的各位呢,也只是把它当作一个入门,然后通过自己去了解更深入的知识。
 
上一篇
Python并行编程实践(上)
下一篇
Windows Terminal 安装及美化