python - asyncio 会在这里帮助我吗?
问题描述
我有一个使用 wxpython4.0.3 开发的小 python 应用程序,它执行一个相当简单的 ETL 类型任务:
- 接受用户输入以选择包含多个子目录的父目录,这些子目录充满 CSV 文件(时间序列数据)。
- 转换每个文件中的数据以符合第三方收件人要求的格式,并将它们写入新文件。
- 将每个新文件压缩到以原始文件的父目录命名的文件中
- 然后,在用户的主动下,应用程序将 zip 文件通过 FTP 传输到第三方以加载到数据存储中。
该应用程序运行良好,但处理数千个 CSV 文件所需的时间非常极端,据我所知,主要是 IO 限制。
asyncio 是一个合理的选择吗,还是任何人都可以提出其他建议?我最初将其编写为 CLI,并通过使用 pypy 看到了显着的性能提升,但是当我为其他人开发 UI 时,我不愿意将 pypy 与 wxpython 结合起来。
感谢您的指导。
解决方案
如果您看到使用 PyPy 而不是 CPython 显着加速,这意味着您的代码可能不是I/O 绑定的。这意味着使 I/O 异步不会有太大帮助。另外,这也将是额外的工作,因为您必须将所有 CPU 繁重的任务重组为可以await
重复的小块,这样它们就不会阻塞其他任务。
因此,您可能希望在此处使用多个进程。
最简单的解决方案是使用 a concurrent.futures.ProcessPoolExecutor
: 只需将任务扔给 executor,它就会在子进程上运行它们并返回一个Future
.
与 using 不同asyncio
,您根本不必更改这些任务。他们可以通过循环csv
模块来读取文件,在一个大块中处理它,甚至使用同步ftplib
模块,而无需担心任何人会阻塞其他人。只有您的顶级代码需要更改。
但是,您可能需要考虑将代码拆分为wx
您在 CPython 中运行的 GUI,以及您subprocess
在 PyPy 中运行的多处理引擎,然后它ProcessPoolExecutor
也会从 PyPy 中分离出来。这将需要更多的工作,但这意味着您将获得使用 PyPy 的 CPU 优势、使用 CPython 的经过良好测试的 wx 优势以及多处理的并行性。
另一个要考虑的选择是引入像 NumPy 或 Pandas 这样的库,它们可以更快地完成慢速部分(无论是读取和处理 CSV,还是对数千行进行某种元素计算,或其他)(甚至可能释放GIL,这意味着您不需要多处理)。
如果您的代码确实是I/O 绑定代码,并且主要绑定在 FTP 请求上,asyncio
将会有所帮助。但这需要重写大量代码。您需要找到或编写一个驱动的asyncio
FTP 客户端库。而且,如果文件读取占用了您大部分时间,那么将其转换为异步就更难了。
还有将wx
事件循环与asyncio
事件循环集成的问题。您可能能够asyncio
在第二个线程中运行循环,但随后您需要想出某种方式wx
在主线程中的事件循环和asyncio
后台线程中的循环之间进行通信。或者,您可能能够从另一个循环驱动一个循环(或者甚至可能有第三方库为您执行此操作)。但这可能更容易使用(或有更好的第三方库来帮助)诸如twisted
代替asyncio
.
但是,除非您需要大量并发(您可能不需要,除非您有数百个不同的 FTP 服务器可以与之通信),否则线程应该也能正常工作,对代码的更改要少得多。只需使用 a concurrent.futures.ThreadPoolExecutor
,这与使用 a 几乎相同,ProcessPoolExecutor
如上所述。