并行化我的Python程序
我有一个用Python写的程序,它会从一个输入文件中读取一行数据,进行一些处理,然后把结果写入输出文件。我有一台四核的电脑,想要充分利用这四个核心。我觉得有两种方法可以做到这一点:
- 创建多个Python进程,每个进程处理总记录数的1/n。
- 在一个Python进程中为每条输入记录创建多个线程,每个线程处理一条记录。
- 在一个Python进程中创建一个线程池,每个线程执行一条输入记录。
我从来没有使用过Python的多进程功能,能不能请高手们告诉我哪种方法是最好的选择?
3 个回答
第一种方法是正确的答案。
首先,创建和管理多个进程比多个线程要简单得多。你可以使用 multiprocessing
模块,或者像 pyro
这样的工具来处理这些细节。其次,线程需要处理Python的全局解释器锁,这让事情变得更复杂,即使你在Java或C#的线程方面很有经验。而且最重要的是,在多核机器上的性能表现比你想象的要难以预测。如果你没有尝试过并测量两种不同的方法,你对哪种方法更快的直觉可能是错的。
顺便说一下,如果你真的在Java或C#的线程方面是专家,那你可能应该选择使用线程,但要用 Jython
或 IronPython
,而不是CPython。
从多个进程同时读取同一个文件是件麻烦事。有没有办法提前把文件分开呢?
虽然Python有个叫GIL的限制,但Jython和IronPython就没有这个问题。
另外,要确保一个简单的单进程操作不会已经把磁盘的读写速度用到极限。如果已经满了,那你就很难再获得什么提升了。
Python的参考实现(也就是CPython)有一个著名的概念叫做“全局解释器锁”(GIL),这个锁的存在意味着在同一时间内,只有一个线程可以执行Python代码。因此,在Python中,多线程的使用受到很大限制——除非你在C扩展中完成了大量的工作,并且这些扩展能够释放这个锁。
要解决这个问题,最简单的方法是使用multiprocessing
模块。这个模块的使用方式和threading
模块很相似,操作起来也比较简单。在你的情况下,你可以这样使用它(假设数据处理是最复杂的部分):
import multiprocessing
def process_line(line):
# This function is executed in your worker processes. Manipulate the
# line and return the results.
return manipulate(line)
if __name__ == '__main__':
with open('input.txt') as fin, open('output.txt', 'w') as fout:
# This creates a pool of N worker processes, where N is the number
# of CPUs in your machine.
pool = multiprocessing.Pool()
# Let the workers do the manipulation and write the results to
# the output file:
for manipulated_line in pool.imap(process_line, fin):
fout.write(manipulated_line)