首页 > 解决方案 > asyncio 会在这里帮助我吗?

问题描述

我有一个使用 wxpython4.0.3 开发的小 python 应用程序,它执行一个相当简单的 ETL 类型任务:

该应用程序运行良好,但处理数千个 CSV 文件所需的时间非常极端,据我所知,主要是 IO 限制。

asyncio 是一个合理的选择吗,还是任何人都可以提出其他建议?我最初将其编写为 CLI,并通过使用 pypy 看到了显着的性能提升,但是当我为其他人开发 UI 时,我不愿意将 pypy 与 wxpython 结合起来。

感谢您的指导。

标签: pythonwxpythonpython-asyncio

解决方案


如果您看到使用 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将会有所帮助。但这需要重写大量代码。您需要找到或编写一个驱动的asyncioFTP 客户端库。而且,如果文件读取占用了您大部分时间,那么将其转换为异步就更难了。

还有将wx事件循环与asyncio事件循环集成的问题。您可能能够asyncio在第二个线程中运行循环,但随后您需要想出某种方式wx在主线程中的事件循环和asyncio后台线程中的循环之间进行通信。或者,您可能能够从另一个循环驱动一个循环(或者甚至可能有第三方库为您执行此操作)。但这可能更容易使用(或有更好的第三方库来帮助)诸如twisted代替asyncio.

但是,除非您需要大量并发(您可能不需要,除非您有数百个不同的 FTP 服务器可以与之通信),否则线程应该也能正常工作,对代码的更改要少得多。只需使用 a concurrent.futures.ThreadPoolExecutor,这与使用 a 几乎相同,ProcessPoolExecutor如上所述。


推荐阅读