operator<<
いくつかのログを見ていると、プロファイラーでint の書式設定などに多くの時間を費やしていることに気付きました。ostream::operator<<
int(およびおそらくdouble)をフォーマットするときに呼び出されるたびに使用される共有ロックがあるようです。さらに調査した結果、次の例に絞り込みました。
フォーマットを行うために使用する Loop1 ostringstream
:
DWORD WINAPI doWork1(void* param)
{
int nTimes = *static_cast<int*>(param);
for (int i = 0; i < nTimes; ++i)
{
ostringstream out;
out << "[0";
for (int j = 1; j < 100; ++j)
out << ", " << j;
out << "]\n";
}
return 0;
}
ostringstream
同じことを使用して int 形式以外のすべてを行うLoop2 は、次のように行われitoa
ます。
DWORD WINAPI doWork2(void* param)
{
int nTimes = *static_cast<int*>(param);
for (int i = 0; i < nTimes; ++i)
{
ostringstream out;
char buffer[13];
out << "[0";
for (int j = 1; j < 100; ++j)
{
_itoa_s(j, buffer, 10);
out << ", " << buffer;
}
out << "]\n";
}
return 0;
}
テストでは、各ループを 1、2、3、および 4 スレッドで何度も実行しました (4 コアのマシンを使用しています)。試行回数は一定です。出力は次のとおりです。
doWork1: all ostringstream
n Total
1 557
2 8092
3 15916
4 15501
doWork2: use itoa
n Total
1 200
2 112
3 100
4 105
ご覧のとおり、ostringstream を使用したときのパフォーマンスはひどいものです。スレッドを追加すると 30 倍悪化しますが、itoa は約 2 倍速くなります。
1 つのアイデアは、この記事で M$ が_configthreadlocale(_ENABLE_PER_THREAD_LOCALE)
推奨するように使用することです。それは私を助けないようです。同様の問題を抱えていると思われる別のユーザーがいます。
アプリケーションで並行して実行される複数のスレッドで int をフォーマットできる必要があります。この問題を考えると、これを機能させる方法を理解するか、別のフォーマット ソリューションを見つける必要があります。整数型と浮動小数点型に対してオーバーロードされた operator<< を使用して単純なクラスをコーディングし、基になるストリームで operator<< を呼び出すだけのテンプレート バージョンを作成することができます。operator<<(ostream&,T)
少し醜いですが、私はそれを機能させることができると思いますostream
.
また、これが Microsoft Visual Studio 2005 でビルドされていることも明確にする必要があります。この制限は、標準ライブラリの実装に起因すると考えています。