私のアプリケーションは、SD カードから ~100MB のファイルを解析することから始めます。解析には数分かかります。概観すると、私の PC では、同じファイルの解析に数秒かかります。
MatcherとPatternを使用して単純にパーサーを実装することから始めましたが、DDMS によると、時間の 90% が正規表現の計算に費やされていました。そして、ファイルの解析に 30 分以上かかりました。パターンはとてつもなくシンプルで、行は次のように構成されています。
ID (a number) <TAB> LANG (a 3-to-5 character string) <TAB> DATA (the rest)
String.splitを試してみることにしました。おそらく、この関数自体が正規表現を使用している可能性があるため、大幅な改善は見られませんでした。その時点で、私はパーサーを完全に書き直すことに決め、最終的には次のようになりました。
protected Collection<Sentence> doInBackground( Void... params ) {
BufferedReader reader = new BufferedReader( new FileReader( sentenceFile ) );
String currentLine = null;
while ( (currentLine = reader.readLine()) != null ) {
treatLine( currentLine, allSentences );
}
reader.close();
return allSentences;
}
private void treatLine( String line, Collection<Sentence> allSentences ) {
char[] str = line.toCharArray();
// ...
// treat the array of chars into an id, a language and some data
allSentences.add( new Sentence( id, lang, data ) );
}
そして、私は大きな後押しに気づきました。30分ではなく数分かかりました。しかし、これでは満足できなかったので、プロファイリングを行ったところ、ボトルネックがBufferedReader.readLineであることがわかりました。私は疑問に思いました: IO バウンドである可能性がありますが、実際には必要のない中間バッファーを埋めるのに多くの時間がかかる可能性もあります。そこで、FileReader を直接使用して全体を書き直しました。
protected Collection<Sentence> doInBackground( Void... params ) {
FileReader reader = new FileReader( sentenceFile );
int currentChar;
while ( (currentChar = reader.read()) != -1 ) {
// parse an id
// ...
// parse a language
while ( (currentChar = reader.read()) != -1 ) {
// do some parsing stuff
}
// parse the sentence data
while ( (currentChar = reader.read()) != -1 ) {
// parse parse parse
}
allSentences.add( new Sentence( id, lang, data ) );
}
reader.close();
}
そして、パフォーマンスが非常に悪いことに気づき、かなり驚きました。明らかに、ほとんどの時間はFileReader.readで費やされます。char を読み取るだけでもかなりのコストがかかると思います。
今、私は少しインスピレーションを失っています。ヒントはありますか?