python编程100例,50行的python游戏代码
Python是一种非常适合处理数据和自动完成重复性工作的编程语言。在我们用数据训练机器学习模型之前,通常需要对数据进行预处理,而Python非常适合完成这项工作。例如,成千上万的图像需要调整大小。用Python没问题!你几乎总能找到可以轻松完成数据处理的Python库。
不过,Python虽然易学易用,但并不是最快的语言。默认情况下,Python程序使用CPU作为单个进程运行。但是如果你的电脑是近几年配置的,一般是四核处理器,也就是4个CPU。这意味着,当您等待Python脚本完成数据处理时,您的计算机实际上有75%或更多的计算资源只是坐在那里无所事事!
今天,边肖将教你如何通过并行运行Python函数来充分利用计算机的处理能力。得益于Python的concurrent.futures模块,我们可以把一个常见的数据处理脚本变成一个只需要10行代码就可以并行处理数据的脚本,速度提高了4倍。
普通的Python数据处理方法比如我们有一个装满图像数据的文件夹,想用Python为每张图像创建缩略图。
下面是一个简短的脚本,它使用Python内置的glob函数获取文件夹中所有JPEG图像的列表,然后使用Pillow图像处理库为每张图像保存一个大小为128像素的缩略图:
import glob import OS from pil import image def make _ image _ thumbnail(filename):# thumbnail将被命名为 original _ filename _ thumbnail . jpg base _ filename,File _ extension=OS . path . split ext(filename)thumbnail _ filename=f { base _ filename } _ thumbnail { File _ extension } #创建并保存thumbnail image=image . open(filename)image . thumbnail(size=(128,128))image . save(thumbnail _ filename, JPEG )返回thumbnail _jpg )对于每个图像:thumbnail _ file=make _ image _ thumbnail(image _ file)print(f 将{image _ file}的缩略图保存为{thumbnail _ file} )
首先,获得您想要处理的文件(或其他数据)的列表。
写一个辅助函数,可以处理上面文件的单个数据。
使用for循环调用辅助函数并处理每个数据,一次一个。
让我们用一个包含1000张JPEG图像的文件夹来测试这个脚本,看看它需要运行多长时间:
$ time python 3 thumbnails _ 1 . pya 1430028941 _ 4 db 9 dedd 10 . jpg的缩略图保存为1430028941 _ 4 db 9 dedd 10 _ thumbnail . jpg[.大约1000多行输出.]Real 0m 8.956 suser 0m 7.086 ssys 0m 0.743s运行程序用了8.9秒,但电脑的真实工作强度是多少?
让我们再次运行程序,查看程序运行时的活动监视器:
电脑75%的处理资源都是闲置的!这是什么情况?
这个问题的原因是我的电脑有4个CPU,而Python只用了一个。所以程序只用一个CPU全力,其他三个什么都不用。因此,我需要一种方法来将工作负载分成四个独立的部分,以便我可以并行处理。好在Python里有一个方法可以很轻松的让我们做到!
尝试创建一个多进程。这是一种允许我们并行处理数据的方法:
1.将JPEG文件分成4个小块。
2.运行Python解释器的4个独立实例。
3.让每个Python实例处理这4段数据中的一段。
4.综合这四个部分的处理结果,得到最终的结果列表。
四个Python复制程序运行在四个独立的CPU上,处理工作量应该是一个CPU的四倍左右吧?
最棒的是,Python为我们完成了这项工作中最麻烦的部分。我们只需要告诉它想要运行哪个函数,以及要使用多少个实例,剩下的事情就交给它了。整个过程我们只需要改三行代码。
首先,我们需要导入concurrent.futures库,它内置于Python中:
接下来,我们需要告诉Python启动4个额外的Python实例。我们通过让Python创建一个进程池来实现这一点:
以concurrent . futures . processpoolexecutor()为执行器:默认情况下,它会为你电脑上的每个CPU创建一个Python进程,所以如果你有4个CPU,它会启动4个Python进程。
最后一步是让创建的进程池使用这4个进程来执行我们在数据列表上的辅助功能。为了完成这一步,我们将循环现有的:
For image _ file in glob.glob (*。jpg ):thumbnail _ file=make _ image _ thumbnail(image _ file)替换为对executor.map()的新调用:
Image _ files=glob.glob (*。jpg) for image _ file,thumbnail _ file in zip(image _ files,executor . map(make _ image _ thumbnail,image _ files)):executor . map()函数需要输入一个辅助函数和要处理的数据列表。这个功能可以帮我完成所有麻烦的任务,包括把列表分成多个子列表,给每个子进程发送子列表,运行子进程,合并结果。干得好!
这也可以为我们返回每个函数调用的结果。Executor.map()函数将以与输入数据相同的顺序返回结果。于是我用Python的zip()函数作为快捷方式,一步得到原始文件名和每一步的匹配结果。
下面是经过这三次修改后的程序代码:
import glob import OS from PIL import image import concurrent . futures def make _ image _ Thumbnail(filename):# Thumbnail将被命名为 original _ filename _ Thumbnail . jpg base _ filename,File _ ext=OS . path . split ext(filename)Thumbnail _ filename=f { base _ filename } _ Thumbnail { File _ extension } #创建并保存Thumbnail image=image . open(filename)image . Thumbnail(size=(128,128))image . save(Thumbnail _ filename, JPEGjpg) #处理文件列表,但是通过进程池分工,使用所有CPU!对于image _ file,zip中的thumbnail _ file(image _ files,executor . map(make _ image _ thumbnail,image _ files)): print (f 将{image _ file}的一个缩略图保存为{thumbnail _ file} )让我们运行一下这个脚本,看看它。
$ time python 3 thumbnails _ 2 . pya 1430028941 _ 4 db 9 dedd 10 . jpg的缩略图保存为1430028941 _ 4 db 9 dedd 10 _ thumbnail . jpg[.大约1000多行输出.]REAL 0m 2.274 user0m 8.959 ssys 0m 0.951s脚本2.2秒处理完数据!比原版快4倍!我们能够更快处理数据的原因是我们使用了四个CPU而不是一个。
但如果你仔细观察,你会发现“用户”时间几乎是9秒。为什么程序的处理时间是2.2秒,但不知为何运行时间还是9秒?似乎不太可能,不是吗?
这是因为“用户”时间是所有CPU时间的总和。我们完成工作的CPU时间总和是一样的,都是9秒,但是我们用4个CPU来完成,实际数据处理时间只有2.2秒!
注意:启动更多的Python进程,将数据分配给子进程是需要时间的,所以这种方法并不能保证速度总能大幅提升。如果你必须处理一个非常大的数据集,这里有一篇文章是关于把数据集分成多少部分的。你可以看一下,对你会有很大的帮助。
这种方法总能加快我的数据处理脚本吗?如果您有一个数据列表,并且每个数据都可以单独处理,那么使用我们在这里称之为进程池的方法是一个提高速度的好方法。以下是一些合适的并行处理示例:
从一系列单独的web服务器日志中获取统计数据。从一堆XML、CSV和JSON文件中解析数据。对大量图像数据进行预处理,建立机器学习数据集。但是也要记住,进程池不是万能的。使用进程池需要在独立的Python处理进程之间来回传递数据。如果你要处理的数据在处理过程中无法有效传输,这种方法是行不通的。简而言之,您正在处理的数据必须是Python知道如何处理的类型。
同时,数据不能以预期的顺序进行处理。如果需要上一步的处理结果才能进行下一步,这个方法也不行。
GIL的问题呢?你可能知道Python有个叫全局解释器锁的东西,也就是GIL。这意味着即使你的程序是多线程的,每个线程也只能执行一条Python指令。GIL确保任何时候都只有一个Python线程在执行。换句话说,多线程Python代码不能并行运行,所以不能充分利用多核CPU。
但是进程池可以解决这个问题!因为我们运行独立的Python实例,所以每个实例都有自己的GIL。这样我们就得到可以并行处理的Python代码了!
不要怕并行处理!使用concurrent.futures库,Python允许您简单地修改脚本,并立即让计算机上的所有CPU工作。不要害怕尝试这个方法。一旦您掌握了它,它就像for循环一样简单,但它可以让您的数据处理脚本飞得更快。
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。