性能:使用Python读取文件的最快方式

时间:2014-11-26 22:54:14

标签: python performance io

所以我有大约400个文件,大小从10kb到56mb,文件类型是.txt / .doc(x)/ .pdf / .xml,我必须全部阅读。我的文件阅读基本上是:

#for txt files
with open("TXT\\" + path, 'r') as content_file:
    content = content_file.read().split(' ')

#for doc files using pydoc
contents = '\n'.join([para.text for para in doc.paragraphs]).encode("ascii","ignore").decode("utf-8").split(' ')

#for pdf files using pypdf2
for i in range(0, pdf.getNumPages()):
    content += pdf.getPage(i).extractText() + "\n"
    content = " ".join(content.replace(u"\xa0", " ").strip().split())
contents = content.encode("ascii","ignore").decode("utf-8").split(' ')

#for xml files using lxml
tree = etree.parse(path)
contents = etree.tostring(tree, encoding='utf8', method='text')
contents = contents.decode("utf-8").split(' ')

但是我注意到甚至阅读了30个文本文件,每个文件大小不到50kb,对它进行操作需要41秒。但如果我用56mb读取一个文本文件需要9秒。因此,我猜测文件I / O会减慢我的速度,而不是我的程序。

有关如何加快此过程的任何想法?也许将每种文件类型分解为4个不同的线程?但是你会如何做到这一点,因为他们共享相同的列表,并且单个列表将在完成后写入文件。

1 个答案:

答案 0 :(得分:1)

如果您在文件I / O上被阻止,正如您所怀疑的那样,可能可能无法做到。

但是,如果你有很大的带宽但是潜在的延迟,并行化到不同的线程可能有所帮助。特别是如果您正在处理网络文件系统或多盘逻辑驱动器。所以,尝试它不会有害。

但是没有理由按文件类型进行;只需使用一个池来处理所有文件。例如,使用futures模块:*

import concurrent.futures

with concurrent.futures.ThreadPoolExecutor(max_workers=4) as executor:
    results = executor.map(process_file, list_of_filenames)

ThreadPoolExecutor比基本线程池稍微聪明一点,因为它可以让你构建可组合的未来,但是在这里你不需要任何这些,所以我只是将它用作基本线程池,因为Python没有其中之一。**

constructor创建了4个线程,以及管理在这些线程上放置任务并获得结果所需的所有队列和其他任何内容。

然后,map方法只遍历list_of_filenames中的每个文件名,创建一个在该文件名上调用process_file的任务,将其提交到池中,然后等待所有要完成的任务。

换句话说,这与写作相同:

results = [process_file(filename) for filename in list_of_filenames]

...除了它使用四个线程并行处理文件。

如果不够清楚,文档中有一些很好的例子。


*如果您使用的是Python 2.x,则需要先安装backport才能使用它。或者您可以使用multiprocessing.dummy.Pool代替,如下所示。

**实际上,它确实在multiprocessing.dummy.Pool中,但是没有很清楚地记录下来。