これを回答済みとしてマークし、速度の問題が実際に発生していると思われる場所に関するより簡単なトピックを開始しました
これまでのすべてのコメントに感謝します。非常に便利です
約 4,000 万個の XML ファイルが (均等ではなく) 約 2 か所に分散しています。60K のサブディレクトリ。構造は 10 桁の番号分割に基づいているため、次のようになります。
12/34/56/78/90/files.xml
単一のフィールドの値を引き出して値とファイル名を出力するファイルに対して実行する perl スクリプトがあります。Perl スクリプトは、深さ 2 のすべてのディレクトリのリスト全体で最大 12 の並列インスタンスを実行する bash スクリプトにラップされ、次に各ディレクトリをたどって最下層でファイルを見つけたら処理します。
複数の実行からディスク キャッシュを取得すると、プロセスの 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 が問題を引き起こしているように見えるため、perl スクリプトよりも python スクリプトの方がはるかに効率が悪いということです。
うまくいけば、それで十分な背景があります。私の質問は、アイデアが不足しているため、愚かなことをしているのか、トリックを見逃しているのかということですが、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";
}
}