この関数は、文字列から double の配列を読み取ります。
vector<double> parseVals(string& str) {
stringstream ss(str);
vector<double> vals;
double val;
while (ss >> val) vals.push_back(val);
return vals;
}
100 万個の数字を含む文字列で呼び出すと、関数の実行に 7.8 秒かかります (Core i5、3.3GHz)。これは、1 つの数値を解析するために 25000 の CPU サイクルが費やされることを意味します。
user315052 は、同じコードが彼のシステムで桁違いに高速に実行されることを指摘しており、さらにテストを行ったところ、異なるシステムやコンパイラ間で非常に大きなパフォーマンスの違いが示されました (user315052 の回答も参照してください)。
1. Win7, Visual Studio 2012RC or Intel C++ 2013 beta: 7.8 sec
2. Win7, mingw / g++ 4.5.2 : 4 sec
3. Win7, Visual Studio 2010 : 0.94 sec
4. Ubuntu 12.04, g++ 4.7 : 0.65 sec
Boost/Spirit ライブラリで優れた代替手段を見つけました。コードは安全で、簡潔で、非常に高速です (VC2012 では 0.06 秒、stringstream よりも 130 倍高速です)。
#include <boost/spirit/include/qi.hpp>
namespace qi = boost::spirit::qi;
namespace ascii = boost::spirit::ascii;
vector<double> parseVals4(string& str) {
vector<double> vals;
qi::phrase_parse(str.begin(), str.end(),
*qi::double_ >> qi::eoi, ascii::space, vals);
return vals;
}
これにより、実用的な観点からは問題が解決されますが、stringstream のパフォーマンスが一貫していない理由を知りたいと思います。ボトルネックを特定するためにプログラムのプロファイルを作成しましたが、STL コードは意味不明に見えます。STL の内部構造に詳しい方からのコメントをお待ちしております。
PS: 最適化は、上記のすべてのタイミングで O2 以上です。プログラム プロファイルでの stringstream のインスタンス化もベクトル図の再割り当てもありません。ほとんどの時間は、抽出オペレーター内で費やされます。