いくつかのテストを実行した後、printf
はcout
よりもはるかに高速であることに気付きました。私はそれが実装に依存していることを知っていますが、私のLinuxボックスではprintf
は8倍高速です。したがって、私の考えは、2つの印刷方法を混合することです。単純な印刷にはcout
を使用し、巨大な出力(通常はループ内)の生成にはprintf
を使用する予定です。他のメソッドに切り替える前にフラッシュすることを忘れない限り、安全だと思います:
cout << "Hello" << endl;
cout.flush();
for (int i=0; i<1000000; ++i) {
printf("World!\n");
}
fflush(stdout);
cout << "last line" << endl;
cout << flush;
いいですか?
更新:すべての貴重なフィードバックに感謝します。答えの要約:トリッキーなソリューションを避けたい場合は、endl
をcout
と一緒に使用しないでください。これは、バッファーを暗黙的にフラッシュするためです。使用する "\n"
代わりに。 largeの出力を生成すると興味深い場合があります。
直接的な答えは、はい、それは大丈夫です。
多くの人が速度を向上させる方法についてさまざまなアイデアを出してきましたが、どちらが最も効果的であるかについてはかなりの意見の相違があるようです。私は簡単なテストプログラムを作成して、少なくともどの手法が何を実行したかを理解することにしました。
_#include <iostream>
#include <string>
#include <sstream>
#include <time.h>
#include <iomanip>
#include <algorithm>
#include <iterator>
#include <stdio.h>
char fmt[] = "%s\n";
static const int count = 3000000;
static char const *const string = "This is a string.";
static std::string s = std::string(string) + "\n";
void show_time(void (*f)(), char const *caption) {
clock_t start = clock();
f();
clock_t ticks = clock()-start;
std::cerr << std::setw(30) << caption
<< ": "
<< (double)ticks/CLOCKS_PER_SEC << "\n";
}
void use_printf() {
for (int i=0; i<count; i++)
printf(fmt, string);
}
void use_puts() {
for (int i=0; i<count; i++)
puts(string);
}
void use_cout() {
for (int i=0; i<count; i++)
std::cout << string << "\n";
}
void use_cout_unsync() {
std::cout.sync_with_stdio(false);
for (int i=0; i<count; i++)
std::cout << string << "\n";
std::cout.sync_with_stdio(true);
}
void use_stringstream() {
std::stringstream temp;
for (int i=0; i<count; i++)
temp << string << "\n";
std::cout << temp.str();
}
void use_endl() {
for (int i=0; i<count; i++)
std::cout << string << std::endl;
}
void use_fill_n() {
std::fill_n(std::ostream_iterator<char const *>(std::cout, "\n"), count, string);
}
void use_write() {
for (int i = 0; i < count; i++)
std::cout.write(s.data(), s.size());
}
int main() {
show_time(use_printf, "Time using printf");
show_time(use_puts, "Time using puts");
show_time(use_cout, "Time using cout (synced)");
show_time(use_cout_unsync, "Time using cout (un-synced)");
show_time(use_stringstream, "Time using stringstream");
show_time(use_endl, "Time using endl");
show_time(use_fill_n, "Time using fill_n");
show_time(use_write, "Time using write");
return 0;
}
_
VC++ 2013(x86バージョンとx64バージョンの両方)でコンパイルした後、これをWindowsで実行しました。 1回の実行からの出力(出力がディスクファイルにリダイレクトされる)は次のようになります。
_ Time using printf: 0.953
Time using puts: 0.567
Time using cout (synced): 0.736
Time using cout (un-synced): 0.714
Time using stringstream: 0.725
Time using endl: 20.097
Time using fill_n: 0.749
Time using write: 0.499
_
予想どおり、結果はさまざまですが、興味深い点がいくつかあります。
私は最近、printf
を強制的に呼び出すようにコードを編集しました。 Anders Kaseorgは、_g++
_が特定のシーケンスprintf("%s\n", foo);
を認識し、puts(foo);
と同等であることを指摘して、それに応じてコードを生成します(つまり、puts
を呼び出すコードを生成します) printf
の代わりに)。フォーマット文字列をグローバル配列に移動し、それをフォーマット文字列として渡すと、同じ出力が生成されますが、printf
ではなくputs
を介して強制的に生成されます。もちろん、いつかはこのあたりで最適化される可能性もありますが、少なくとも今のところ(g ++ 5.1)_g++ -O3 -S
_を使用したテストは、実際にprintf
を呼び出していることを確認します(前のコードはputs
の呼び出しにコンパイルされています)。 。
_std::endl
_をストリームに送信すると、newline
が追加されてストリームがフラッシュされます。 cout.flush()
のその後の呼び出しは不要です。これがcout
とprintf
のタイミングで行われた場合は、リンゴとリンゴを比較していませんでした。
デフォルトでは、CおよびC++の標準出力ストリームは同期されているため、一方に書き込むと他方がフラッシュされるため、明示的なフラッシュは必要ありません。
また、C++ストリームはCストリームに同期されることに注意してください。
したがって、同期を保つために余分な作業を行います。
注意すべきもう1つのことは、ストリームを同じ量でフラッシュすることを確認することです。ストリームを1つのシステムで継続的にフラッシュし、他のシステムではフラッシュしないと、テストの速度に確実に影響します。
一方が他方より速いと仮定する前に、次のことを行う必要があります。
printf
のバッファーサイズを増やすことで、stdout
のパフォーマンスをさらに向上させることができます。
setvbuf (stdout, NULL, _IOFBF, 32768); // any value larger than 512 and also a
// a multiple of the system i/o buffer size is an improvement
I/Oを実行するためのオペレーティングシステムへの呼び出し回数は、ほとんどの場合、最も高価なコンポーネントとパフォーマンスリミッターです。
もちろん、cout
の出力がstdout
と混ざっている場合、バッファーフラッシュは、増加したバッファーサイズの目的を無効にします。
printf
とcout
の間のパフォーマンスを気にする必要はありません。パフォーマンスを向上させたい場合は、フォーマットされた出力をフォーマットされていない出力から分離します。
puts("Hello World\n")
はprintf("%s", "Hellow World\n")
よりもはるかに高速です。 (主にフォーマットのオーバーヘッドによる)フォーマットされたテキストをプレーンテキストから分離したら、次のようなトリックを実行できます。
const char hello[] = "Hello World\n";
cout.write(hello, sizeof(hello) - sizeof('\0'));
フォーマットされた出力を高速化するための秘訣は、文字列に対してすべてのフォーマットを実行してから、文字列(またはバッファー)でブロック出力を使用することです。
const unsigned int MAX_BUFFER_SIZE = 256;
char buffer[MAX_BUFFER_SIZE];
sprintf(buffer, "%d times is a charm.\n", 5);
unsigned int text_length = strlen(buffer) - sizeof('\0');
fwrite(buffer, 1, text_length, stdout);
プログラムのパフォーマンスをさらに改善するには、出力の量を減らします。出力が少ないほど、プログラムは高速になります。副作用として、実行可能ファイルのサイズも小さくなります。
まあ、実際にcoutを使って正直になる理由は考えられません。すべてのファイルに含まれるような非常に単純なことを実行するために巨大でかさばるテンプレートを作成することは、完全に異常です。また、それは可能な限りタイピングが遅くなるように設計されているようで、何百万回も<<<<を入力してからその間に値を入力し、何か>> variableName >>>を偶然取得すると、二度とそれをやりたくありません。
言うまでもなく、std名前空間を含めると、世界は最終的に内破されます。そうしないと、入力の負担がさらに馬鹿げたものになります。
ただし、printfもあまり好きではありません。私にとっての解決策は、私自身の具象クラスを作成し、その中で必要なioスタッフを呼び出すことです。次に、好きな方法で、必要な実装やフォーマットなどを使用して、本当に単純なioを作成できます(一般的に、フロートを常に1つの方法にする必要があります。たとえば、理由もなく800の方法でフォーマットしないようにします。呼び出しごとのフォーマットでは冗談です)。
つまり、入力するのはdout +のようなものです。これは、「+ debugIoType +」の「+ cPlusPlusMethod +」よりも正気です。少なくともIMO。 dout ++;
しかし、あなたはあなたが望むものは何でも持つことができます。たくさんのファイルがあるので、これがコンパイル時間をどれほど改善するかは驚くべきことです。
また、CとC++を混在させることには何の問題もありません。慎重に行う必要があります。最初にCを使用する際に問題を引き起こすものを使用している場合は、CとCを混在させることによる心配は最小限であると言っても安全です。 C++。
C++とCのiomethodsを混在させることは、私のC++の本、FYIに対して推奨されていました。 C関数は、C++が予期する/保持する状態を踏みにじると確信しています。