我有一个使用wxpython4.0.3开发的小python应用程序,它执行以下相当简单的ETL类型任务:
该应用程序运行良好,但是处理数千个CSV文件所需的时间非常长,而且从我所知道的来看,大部分都是IO约束。
异步是追求合理的选择还是有人可以提出其他建议?我最初是作为CLI编写的,使用pypy可以显着提高性能,但是当我为其他人开发UI时,我不愿意将pypy与wxpython结合使用。
感谢您的指导。
答案 0 :(得分:2)
如果通过使用PyPy而不是CPython看到了显着的加速,则表明您的代码可能不受I / O约束。这意味着使I / O异步不会有太大帮助。另外,这也将是额外的工作,因为您必须将所有占用大量CPU的任务重组为小块,这些小块可以反复await
,以便它们不会阻塞其他任务。
因此,您可能要在此处使用多个过程。
最简单的解决方案是使用concurrent.futures.ProcessPoolExecutor
:只需在执行程序上扔任务,它将在子进程上运行它们并返回Future
。
与使用asyncio
不同,您根本不必更改这些任务。他们可以通过遍历csv
模块来读取文件,将其全部处理成一个大块,甚至可以使用同步ftplib
模块,而不必担心有人阻塞其他任何人。只需更改您的顶级代码。
但是,您可能需要考虑将代码分成在CPython中运行的wx
GUI和在PyPy中通过subprocess
运行的多处理引擎,然后分拆{{ 1}}在PyPy中也是如此。这将花费更多的工作,但是这意味着您将获得使用PyPy的CPU优势,经过充分测试的使用CPython的wx优势以及多处理的并行性。
要考虑的另一种选择是引入像NumPy或Pandas这样的库,它们可以做得较慢(无论是读取和处理CSV,还是对数千行进行某种元素计算,等等)。甚至可能释放GIL,这意味着您不需要多处理)。
如果您的代码确实是 的I / O绑定代码,并且主要绑定在FTP请求上,那么ProcessPoolExecutor
会有所帮助。但这需要重写大量代码。您需要找到或编写一个asyncio
驱动的FTP客户端库。而且,如果文件读取花费了您的大部分时间,那么将其转换为异步将更加艰巨。
还存在将asyncio
事件循环与wx
事件循环集成的问题。您可能可以在第二个线程中运行asyncio
循环,但是您需要想出一种在主线程中的asyncio
事件循环和{{ 1}}在后台线程中循环。或者,您可能能够驱动另一个循环(或者甚至可能有第三方库为您完成该循环)。但是,使用wx
而不是asyncio
这样的东西(或者有更好的第三方库来帮助)可能会容易得多。
但是,除非您需要大量的并发(除非您需要与之对话的数百个不同的FTP服务器,否则可能不需要),线程应该也可以正常工作,并且对代码的更改更少。只需使用concurrent.futures.ThreadPoolExecutor
,几乎与上述使用twisted
相同。
答案 1 :(得分:0)
是的,您可能会受益于使用异步库。由于您的大部分时间都花在等待IO上,因此编写良好的异步程序将利用该时间执行其他操作,而不会产生额外的线程/进程的开销。它将很好地扩展。