Python 以极高的开发效率著称,而运行速度则“没那么快”。
虽然,在现代计算机体系架构下,系统的运行效率并不完全取决于编程语言,但程序员仍有可能从编程技巧着手,让自己的代码“跑得更快些”。
对 Python 而言,我们可以通过“并行化”来实现程序的加速。
简单而言,并行计算允许你“同时”执行多个运算任务,这样就可以减少程序运行所需要的总耗时了。
这听起来有点笼统,并且你可能感觉实现起来会有些复杂。别急,请再花大概 50 秒来了解并行计算的实现。
我们来看一个使用 Python 实现并行计算的例子。这个例子仅用到了内建于 Python 中的两个工具,简单实用。
首先,需要一些准备工作。
我们将导入两个模块:collections 和 multiprocessing,以便定义我们需要的数据结构,以及来实现并行计算。import collectionsimport multiprocessing
接着,我们使用“collections.namedtuple”来定义一个新的不可变数据类型:Scientist,它包含 name 和 born 两个属性。Scientist = collections.namedtuple( 'Scientist' , [ 'name', 'born' ])
我们使用这个数据类型定义一组数据:scientists = (Scientist(name='Ada Lovelace', born=1815),Scientist(name='Emmy Noether', born=1882),Scientist(name='Marie Curie', born=1867),Scientist(name='Tu Youyou', born=1930),Scientist(name='Ada Yonath', born=1939),Scientist(name='Vera Rubin', born=1928),Scientist(name='Sally Ride', born=1951),)
然后,我们来定义一个数据处理函数,它接受一个 Scientist 对象,返回一个包含 Scientist 名称和年龄的 dict 对象。def process_item(item):return {'name' : item.name,'age' : 2021 - item.born}
这个 process_item 函数其实就代表了一个典型的数据处理过程。
我们出于演示目的使得它简单明了,但你可以为其提供更多代码,以使得它可以完成更复杂的功能。
现在到了展示并行计算魔法的时候了,请接着再往下浏览最关键的 20 秒。
我们将构建一个进程池,这样就可以将运算分布到宿主机所有可用的 CPU 上。pool = multiprocessing.Pool()
我们需要调用这个 pool 的 map() 方法,以并行批处理的方式将数据处理函数 process_item() 应用到 scientists 元组上。result = pool.map( process_item, scientists )
看官请注意,如何处理批量数据、如何将处理任务分配到多个 CPU 上、如何执行计算任务、以及如何收集处理结果,这些看似复杂的工作都由 multiprocessing 进程池来为我们完成了。很奇妙很厉害吧!
最后,我们该收尾了,花 5 秒时间将运行结果 result 打印到控制台窗口。print( tuple( result ) )
我们需要将这三行代码放在if __name__ == '__main__': 代码块中,否则会报错:AttributeError: module '__main__' has no attribute '__spec__'
应该这样放置代码:if __name__ == '__main__':pool = multiprocessing.Pool()result = pool.map(process_item, scientists)print(tuple(result))
程序代码全部完成。看一下运行结果吧:({'name': 'Ada Lovelace', 'age': 206}, {'name': 'Emmy Noether', 'age': 139}, {'name': 'Marie Curie', 'age': 154}, {'name': 'Tu Youyou', 'age': 91}, {'name': 'Ada Yonath', 'age': 82}, {'name': 'Vera Rubin', 'age': 93}, {'name': 'Sally Ride', 'age': 70})
结语:
怎么样,用 Python 实现并行计算是不是很简单?
当然,你应该理解,技术并非难点,关键是你需要合理设计数据集,以使得它们适于被这个并行框架处理。