嫌Python太慢?并行运算Process Pools三行代码给你4倍提速!

开发 开发工具
Python是适用于处理数据或者把重复任务自动化的绝佳编程语言。有几个网页日志要抓取或者一百万张图片要调整?没问题!你几乎总是能找到对应的Python库帮助您轻松完成任务。

 

[[201332]]

 

 

作者 | Adam Geitgey

 

 

编译 | 元元、Lisa、Saint、Aileen

 

Python绝对是处理数据或者把重复任务自动化的***编程语言。要抓取网页日志?或者要调整一百万张图片?总有对应的Python库让你轻松完成任务。

然而,Python的运营速度一直饱受诟病。默认状态下,Python程序使用单个CPU的单个进程。如果你的电脑是最近十年生产的,多数情况下会有4个及以上CPU核。也就是说,当你在等程序运行结束的时候,你的计算机有75%或者更多的计算资源都是空置的!

让我们来看看如何通过并行运算充分利用计算资源。多亏有Python的concurrent.futures模块,仅需3行代码就可以让一个普通程序并行运行。

一般情况下的Python运行

比如说我们有一个文件夹,里面全是图片文件,我们想给每一张图片创建缩略图。

下面的短程序中我们使用Python自带的glob 函数获取一个包含文件夹中所有图片文件的列表,并用Pillow图片处理库获取每张图片的128像素缩略图。

一般情况下的Python运行

这个程序遵循很常见的数据处理模式:

  1. 从您想处理的一系列文件(或其他数据)开始
  2. 编写一个处理一个数据的辅助函数
  3. 用for循环调动辅助函数,一个一个的去处理数据

让我们用1000张图片来测试这个程序,看看运行时间是多少。

程序运行时间8.9秒,但是计算机的运算资源占用了多少呢?

让我们再跑一次程序,同时查看活动监视器:

计算机有75%空置,这是为什么呢?

问题在于我的计算机有4个CPU核,但是Python只用了其中一个核。即便我的程序把那个CPU核完全占满,但是其他3个CPU核什么也没干。我们需要想办法把整个程序的工作量分成4份然后平行运行。所幸Python可以做到这一点!

让我们来试试并行运算

下面是实现并行运算的一个方法:

  1. 把Jpeg图片文件列表分成4个部分。
  2. 同时跑四个Python解释器。
  3. 让四个解释器分别处理一部分图片文件。
  4. 汇总四个解释器的结果得到最终结果。

四个Python程序分别在4个CPU上运行,跟之前在1个CPU运行相比大概可以达到4倍的速度,对不对?

好消息是Python可以帮我们解决并行运算麻烦的部分。我们仅需要告诉 Python我们想要运行什么函数以及我们希望工作分成多少份,其他部分留给Python。我们只需要修改三行代码。

首先,我们需要导入concurrent.futures库。这个库是Python自带的:

然后,我们需要告诉 Python另外启动4个Python实例。我们通过创建Process Pool来传达指令:

默认设置下,上面的代码会给计算机的每一个CPU创建一个Python进程,所以如果您的计算机有4个CPU,就会开启4个Python进程。

***一步是让Process Pool 用这4个进程在数据列表中执行我们的辅助函数。我们可以把我们之前的for循环替代为:

新代码是调用executor.map()函数

executor.map() 函数调用时需要输入辅助函数和待处理的数据列表。这个函数帮我们完成所有麻烦的工作,把列表分成几个小列表,把小列表分配给每个子进程,运行子进程,以及汇总结果。干得漂亮!

我们也可以得到每次调用辅助函数的结果。executor.map()函数以输入数据顺序返回结果。 Python的zip()函数可以一步获取原始文件名以及相应结果。

下面是经过三步改动之后的程序:

让我们试着运行一下,看看有没有缩短运行时间:

2.274秒程序就运行完了!这便是原来版本的4倍加速。运行时间缩短的原因正是我们这次用4个CPU代替了1个CPU。

但是如果您仔细看看,您会看到“用户(User)”时间大概是接近9秒,如果程序2秒就运行结束了,为什么客户时间会是9秒?这似乎…有哪里不对?

其实这是因为”用户”时间是所有CPU时间的总和。我们和上次一样,用9秒的总CPU

注意:启用Python进程以及给子进程分配数据都会占用时间,因此您不一定能靠这个方法大幅提高速度。如果您处理的数据量很大,这里有一篇“设置chunksize参数的技巧”文章可能可以帮助您:https://docs.python.org/3/library/concurrent.futures.html#concurrent.futures.Executor.map。

这种方法总能帮我的程序提速吗?

当你有一列数据,并且每个数据都可以独立处理的时候,使用Process Pools是一个好方法。这有一些适合使用并行处理的例子:

  1. 从一系列单独的网页服务器日志里抓取数据。
  2. 从一堆XML,CSV和JSON文件中解析数据。
  3. 对大量图片数据做预处理,建立机器学习数据集。

但Process Pools不是***的。使用Process Pool需要在独立的Python处理过程中将数据来回传递。如果你正在使用的数据不能在处理过程中有效的被传递,这种方法就行不通。你处理的数据必须是Python知道怎么搞定的类型

(https://docs.python.org/3/library/pickle.html#what-can-be-pickled-and-unpickled)。

同时,数据不会按照一个预想的顺序被处理。如果你需要前一步的处理结果来进行下一步骤,这种方法也行不通。

那GIL怎么办?

你可能听说过Python有一个全局解释器锁(Global Interpreter Lock,),缩写为GIL。这意味着即使你的程序是多层的,每一层也只有一个Python命令能被执行。GIL确保任何时候都只有一个Python线程执行。 GIL***的问题就是Python的多线程程序并不能利用多核CPU的优势。

但Process Pools能解决这个问题!因为我们在运行单独的Python实例,每个实例都有自己的GIL。这样你就有了真正的并行处理的Python代码!

不要害怕并行处理!

有了concurrent.futures库,Python可以让你简简单单地修改脚本,却能立刻调用你电脑上所有CPU内核开足马力地运行。不要害怕尝试。一旦你会用了,它就像写一个for循环那样简单,但会让整个程序快很多。

原文:

https://medium.com/@ageitgey/quick-tip-speed-up-your-python-data-processing-scripts-with-process-pools-cf275350163a

【本文是51CTO专栏机构大数据文摘的原创译文,微信公众号“大数据文摘( id: BigDataDigest)”】

     大数据文摘二维码

 

戳这里,看该作者更多好文

责任编辑:赵宁宁 来源: 51CTO专栏
相关推荐

2019-06-26 08:37:23

Python数据处理编程语言

2021-12-17 12:12:22

Python 开发数据

2018-10-07 05:27:03

Python代码机器学习

2020-05-06 22:01:52

Excel代码Python

2023-07-31 08:02:28

2018-07-27 09:32:18

Python代码数据

2009-10-27 09:12:50

Visual Stud

2019-10-09 15:51:45

Python 开发编程语言

2021-11-18 10:20:22

代码PDFPython

2021-08-30 15:41:23

代码开源微软

2020-06-09 14:33:15

PythonCython代码

2020-08-12 09:14:45

Python验证码工具

2023-08-14 07:42:01

模型训练

2022-04-09 09:11:33

Python

2019-12-25 14:08:50

Pandas数据计算

2018-03-28 14:10:10

GoPython代码

2017-04-13 19:20:18

Python代码并行任务

2020-08-19 10:30:25

代码Python多线程

2020-05-20 12:50:32

代码线性方程开发

2022-05-11 09:02:27

Python数据库Excel
点赞
收藏

51CTO技术栈公众号