【发布时间】:2014-10-01 22:27:51
【问题描述】:
将此标记为已回答并围绕速度问题真正出现的地方开始一个更简单的主题
Python slow read performance issue
感谢迄今为止所有的 cmets,非常有用
我有大约 4000 万个 XML 文件(不均匀)分布在大约 400 万个 XML 文件中。 60K 子目录,结构基于 10 位数字拆分,所以:
12/34/56/78/90/files.xml
我有一个 perl 脚本,它针对文件运行,提取单个字段的值并打印值和文件名。 Perl 脚本封装在一个 bash 脚本中,该脚本在深度 2 的所有目录列表中运行最多 12 个并行实例,然后向下遍历每个实例,并在找到它们时在底层处理文件。
从多个运行中取出磁盘缓存,进程的 unix 时间返回大约:
real 37m47.993s
user 49m50.143s
sys 54m57.570s
我想将它迁移到 python 脚本(作为学习练习和测试),因此创建了以下内容(在大量阅读各种 python 方法之后):
import glob, os, re
from multiprocessing import Pool
regex = re.compile(r'<field name="FIELDNAME">([^<]+)<', re.S)
def extractField(root, dataFile):
line = ''
filesGlob = root + '/*.xml'
global regex
for file in glob.glob(filesGlob):
with open(file) as x:
f = x.read()
match = regex.search(f)
line += file + '\t' + match.group(1) + '\n'
dataFile.write(line)
def processDir(top):
topName = top.replace("/", "")
dataFile = open('data/' + topName + '.data', 'w')
extractField(top, dataFile)
dataFile.close()
filesDepth5 = glob.glob('??/??/??/??/??')
dirsDepth5 = filter(lambda f: os.path.isdir(f), filesDepth5)
processPool = Pool(12)
processPool.map(processDir, dirsDepth5)
processPool.close()
processPool.join()
但是无论我如何在运行时对内容进行切片,unix 时间都会给我这样的结果:
real 131m48.731s
user 35m37.102s
sys 48m11.797s
如果我在单个线程中针对一小部分子集(最终被完全缓存)运行 python 和 perl 脚本,因此没有磁盘 io(根据 iotop),那么脚本运行的时间几乎相同。
目前我能想到的唯一结论是,文件 io 在 python 脚本中的效率远低于在 perl 脚本中的效率,因为似乎是 io 导致了问题。
所以希望这是足够的背景知识,我的问题是我是在做一些愚蠢的事情还是错过了一个技巧,因为我已经没有想法了,但无法相信 io 会导致处理时间出现如此大的差异。
感谢任何指针,并将根据需要提供更多信息。
谢谢
硅
Perl 脚本参考如下:
use File::Find;
my $cwd = `pwd`;
chomp $cwd;
find( \&hasxml, shift );
sub hasxml {
if (-d) {
my @files = <$_/*.xml>;
if ( scalar(@files) > 0 ) {
process("$cwd/${File::Find::dir}/$_");
}
}
}
sub process {
my $dir = shift;
my @files = <$dir/*.xml>;
foreach my $file (@files) {
my $fh;
open( $fh, "< $file" ) or die "Could not read file <$file>";
my $contents = do { local $/; <$fh> };
close($fh);
my ($id) = $contents =~ /<field name="FIELDNAME">([^<]+)<\/field>/s;
print "$file\t<$id>\n";
}
}
【问题讨论】:
-
也许这会对你有所帮助:stackoverflow.com/questions/14863224/… 我认为你应该分析你的应用程序,看看它在哪里花费的时间最多,否则它有点猜测......
-
我会看看谢谢,啊应该已经添加了我正在阅读的 XML 文件,每个文件的大小最多为 4K,但我会尝试提到的缓冲来查看。我尝试进行分析,但是当我运行 - python -m cProfile script.py it barfs 时,我怀疑它不知道如何处理多处理元素,但我承认我没有详细查看错误。
-
user/sys 更低(暗示 python 更快)但 real 更高(暗示我们没有得到并行化)......父/子协议很重要。试试
processPool.map(processDir, dirsDepth5, chunksize=16),它会以更大的批量发送作业,看看是否会有所不同。 -
有趣的是没有看到那个参数,将尝试一下如何分析多进程脚本已经阅读了一些关于如何在代码中而不是从命令行中执行它的帖子我读过多进程脚本不适合!
-
另一个想法, map() 建立了一个结果列表——在你的例子中是 4000 万。试试
for _ in processPool.imap_unordered(processDir, dirsDepth5, chunksize=16): pass。
标签: python perl python-multiprocessing