当前位置: 首页 > 科技观察

三行Python代码可以让你的数据处理速度比别人快4倍

时间:2023-03-12 04:42:57 科技观察

Python是一种非常适合处理数据和自动化重复性任务的编程语言。在我们使用数据训练机器学习模型之前,我们通常需要对数据进行预处理,而Python非常适合这个工作。比如你需要调整几十万张图片的大小,用Python是没问题的!您几乎总能找到一个可以轻松进行数据操作的Python库。然而,尽管Python易学易用,但它并不是运行速度最快的语言。默认情况下,Python程序使用一个CPU作为单个进程运行。但是,如果你近几年配置过电脑,一般都是四核处理器,也就是有4个CPU。这意味着在你等待Python脚本完成数据处理工作的同时,你的电脑75%甚至更多的计算资源实际上是闲置在那里的!今天,我将教您如何通过并行运行Python函数来充分利用计算机的全部处理能力。得益于Python的concurrent.futures模块,我们只需要3行代码就可以将一个普通的数据处理脚本变成一个可以并行处理数据的脚本,提速4倍。常见的Python数据处理方法例如:我们有一个装满图像数据的文件夹,想使用Python为每个图像创建缩略图。这是一个简短的脚本,它使用Python的内置glob函数获取文件夹中所有JPEG图像的列表,然后使用Pillow图像处理库为每个图像保存大小为128像素的缩略图:这个脚本遵循一个简单的模式你会在数据处理脚本中经常看到这种方法:首先获取要处理的文件(或其他数据)的列表,然后编写一个可以处理上述文件的单个数据的辅助函数。使用for循环调用辅助函数来处理每条数据,一次一个。让我们用一个包含1000张JPEG图片的文件夹来测试这个脚本,看看它运行需要多长时间:运行该程序需要8.9秒,但计算机的实际工作负载如何?我们再运行一??下程序,看看程序运行时的活动监视器:计算机75%的处理资源是空闲的!这里发生了什么事?出现这个问题的原因是我的电脑有4个CPU,而Python只用了一个。所以程序只是试图使用其中一个CPU,而其他3个什么都不做。所以我需要一种方法将工作负载分成4个独立的部分,我可以并行处理这些部分。幸运的是,Python中有一种方法可以让我们轻松搞定!尝试创建多个进程下面是一种允许我们并行处理数据的方法:将JPEG文件分成4个小块。运行4个独立的Python解释器实例。让每个Python实例处理这4条数据中的一条。结合这4部分的处理结果,得到最终的结果列表。在4个独立的CPU上运行的4个Python副本应该能够处理比一个CPU多4倍的工作,对吗?最重要的是,Python已经为我们完成了困难的部分。我们只需告诉它我们要运行哪个函数以及要使用多少个实例,剩下的就由它来完成。整个过程我们只需要改动3行代码。首先我们需要导入Python内置的concurrent.futures库:接下来,我们需要告诉Python启动4个额外的Python实例。我们通过让Python创建一个进程池来做到这一点:默认情况下:它将为您计算机上的每个CPU创建一个Python进程,因此如果您有4个CPU,将启动4个Python进程。最后一步:让创建的ProcessPool使用这4个进程在datalist上执行我们的辅助功能。要完成这一步,我们需要用一个新的调用executor.map()来替换现有的for循环:调用executor.map()函数时,需要输入一个辅助函数和一个待处理的数据列表。这个函数为我完成了所有艰苦的工作,包括将列表拆分为子列表、将子列表发送到每个子进程、运行子进程、合并结果等。干得好!这也向我们返回了每个函数调用的结果。Executor.map()函数以与输入数据相同的顺序返回结果。所以我用Python的zip()函数作为快捷方式一步步获取原始文件名和每一步的匹配结果。下面是这三个变化后的程序代码:让我们运行这个脚本,看看它是否更快地完成了数据处理:脚本在2.2秒内处理了数据!比原版快4倍!之所以能够更快地处理数据,是因为我们使用了4个CPU,而不是1个。但如果仔细观察,“用户”时间几乎是9秒。那为什么程序处理时间是2.2秒,不知为何运行时间还是9秒呢?这似乎不太可能?这是因为“用户”时间是所有CPU时间的总和,我们最终用相同的CPU时间来完成工作,也就是9秒,但是我们用了4个CPU来完成,而实际的数据处理时间只有2.2秒!注意:启动更多Python进程并将数据分配给子进程需要时间,因此依赖此方法并不总是能保证较大的加速。这种方法是否总能加快我的数据处理脚本的速度?如果你有一列数据,并且每个数据都可以单独处理,那么使用我们这里所说的ProcessPools是一个很好的提速方式。以下是一些适用于并行处理的示例:从一系列单独的Web服务器日志中抓取统计信息。从一堆XML、CSV和JSON文件中解析数据。预处理大量图像数据并构建机器学习数据集。但也请记住,进程池不是唯一的。使用ProcessPool需要在独立的Python处理进程之间来回传递数据。如果您正在处理的数据在处理过程中无法有效传递,则此方法将不起作用。简而言之,您正在处理的数据必须是Python知道如何处理的类型。同时,无法按预期的顺序处理数据。如果您需要上一步的结果才能继续下一步,这也不起作用。GIL问题呢?你可能知道Python有一个东西叫做全局解释器锁(GlobalInterpreterLock),或者GIL。这意味着即使你的程序是多线程的,每个线程也只能执行一条Python指令。GIL确保在任何时候只有一个Python线程执行。换句话说:多线程Python代码无法真正并行运行以充分利用多核CPU。但是ProcessPool可以解决这个问题!由于我们运行的是不同的Python实例,因此每个实例都有自己的GIL。这样我们就得到了可以真正并行处理的Python代码!不要害怕并行处理!借助concurrent.futures库,Python允许您简单地修改脚本并立即将计算机上的所有CPU投入工作。不要害怕尝试这种方法,一旦掌握了它,它就像for循环一样简单,并且可以让您的数据处理脚本开始工作。

猜你喜欢