7

coutを使用して長い文字列(char *)を印刷すると、Windows 7、Vista、およびLinux(パテを使用)では、WindowsではVisual C ++ 2008、LinuxではG++を使用して一度に1文字ずつ画面に印刷されるようです。Printfは非常に高速で、私のプロジェクトのほとんどの印刷では、実際にcoutからprintfに切り替えました。この質問は私だけがこの問題を抱えているように見えるので、これは私を混乱させます。

私はそれが私のコンプでカウトのズボンを打ち負かすように見えるカウトの交換を書いた-

class rcout
{
public:
    char buff[4096];
    unsigned int size;
    unsigned int length;

    rcout()
    {
        size = 4096;
        length = 0;
        buff[0] = '\0';
    }

    ~rcout()
    {
        printf("%s", buff);
    }

    rcout &operator<<(char *b)
    {
        strncpy(buff+length, b, size-length);
        unsigned int i = strlen(b);
        if(i+length >= size)
        {
            buff[size-1] = '\0';
            printf("%s", buff);
            b += (size-length) -1;
            length = 0;
            return (*this) << b;
        }
        else
            length += i;
        return (*this);
    }

    rcout &operator<<(int i)
    {
        char b[32];
        _itoa_s(i, b, 10);
        return (*this)<<b;
    }

    rcout &operator<<(float f)
    {
        char b[32];
        sprintf_s(b, 32, "%f", f);
        return (*this)<<b;
    }
};

int main()
{
    char buff[65536];
    memset(buff, 0, 65536);

    for(int i=0;i<3000;i++)
        buff[i] = rand()%26 + 'A';

    rcout() << buff << buff <<"\n---"<< 121 <<"---" << 1.21f <<"---\n";
    Sleep(1000);
    cout << "\n\nOk, now cout....\n\n";
    cout << buff << buff <<"\n---"<< 121 <<"---" << 1.21f <<"---\n";
    Sleep(1000);
    cout << "\n\nOk, now me again....\n\n";
    rcout() << buff << buff <<"\n---"<< 121 <<"---" << 1.21f <<"---\n";
    Sleep(1000);

    return 0;
}

coutが私にとってとてもゆっくりと印刷している理由はありますか?

4

8 に答える 8

12

:この実験結果はMSVCで有効です。ライブラリの他の実装では、結果は異なります。

printf よりも(はるかに)高速である可能性coutがあります。実行時にフォーマット文字列を解析しますがprintf、必要な関数呼び出しははるかに少なく、実際には、と比較して同じジョブを実行するために必要な命令の数は少なくなりますcout。これが私の実験の要約です:

静的命令の数

一般に、coutより多くのコードを生成しますprintf。いくつかの形式で印刷するための次のcoutコードがあるとします。

os << setw(width) << dec << "0x" << hex << addr << ": " << rtnname <<
  ": " << srccode << "(" << dec << lineno << ")" << endl;

最適化されたVC++コンパイラでは、約188バイトのコードが生成されます。printfただし、ベースのコードを置き換える場合は、 42バイトしか必要ありません。

動的に実行される命令の数

静的命令の数は、静的バイナリコードの違いを示しているだけです。さらに重要なのは、実行時に動的に実行される実際の命令数です。また、簡単な実験を行いました。

テストコード:

int a = 1999;
char b = 'a';
unsigned int c = 4200000000;
long long int d = 987654321098765;
long long unsigned int e = 1234567890123456789;
float f = 3123.4578f;
double g = 3.141592654;

void Test1()
{
    cout 
        << "a:" << a << “\n”
        << "a:" << setfill('0') << setw(8) << a << “\n”
        << "b:" << b << “\n”
        << "c:" << c << “\n”
        << "d:" << d << “\n”
        << "e:" << e << “\n”
        << "f:" << setprecision(6) << f << “\n”
        << "g:" << setprecision(10) << g << endl;
}

void Test2()
{
    fprintf(stdout,
        "a:%d\n"
        "a:%08d\n"
        "b:%c\n"
        "c:%u\n"
        "d:%I64d\n"
        "e:%I64u\n"
        "f:%.2f\n"
        "g:%.9lf\n",
        a, a, b, c, d, e, f, g);
    fflush(stdout);
}

int main()
{
    DWORD A, B;
    DWORD start = GetTickCount();
    for (int i = 0; i < 10000; ++i)
        Test1();
    A = GetTickCount() - start;

    start = GetTickCount();
    for (int i = 0; i < 10000; ++i)
        Test2();
    B = GetTickCount() - start;
    
    cerr << A << endl;
    cerr << B << endl;
    return 0;
}

Test1(cout)の結果は次のとおりです。

  • 実行された命令の数:423,234,439
  • メモリのロード/ストアの数:約。320,000および980,000
  • 経過時間:52秒

では、どうprintfですか?これはTest2の結果です:

  • 実行された命令の数:164,800,800
  • メモリのロード/ストアの数:約。70,000および180,000
  • 経過時間:13秒

このマシンとコンパイラでprintfは、はるかに高速coutでした。実行された命令の数と、ロード/ストアの数(キャッシュミスの数を示す)の両方で、3〜4倍の違いがあります。

私はこれが極端なケースであることを知っています。coutまた、 32/64ビットのデータを処理していて、32/64プラットフォームの独立性が必要な場合は、これがはるかに簡単であることに注意してください。常にトレードオフがあります。タイプをチェックするときに使用しているcoutのは非常にトリッキーです。

さて、coutMSVSではただひどいです:)

于 2009-11-15T01:53:39.413 に答える
9

別のコンピューターでこれと同じテストを試すことをお勧めします。なぜこれが起こっているのかについて、私には良い答えがありません。私が言えるのは、coutとprintfの速度の違いに気づいたことがないということだけです。また、Linuxでgcc 4.3.2を使用してコードをテストしましたが、違いはありませんでした。

そうは言っても、coutを独自の実装に簡単に置き換えることはできません。実際、coutはstd :: ostreamのインスタンスであり、iostream演算子をオーバーロードする他のクラスとの相互運用性に必要な多くの機能が組み込まれています。

編集:

言う人は誰でも、単に間違っているprintfよりも常に速いです。 minjangによって投稿されたテストコードを、gcc4.3.2と-O2フラグを使用して64ビットAMDAthlon X2で実行したところ、coutの方が実際に高速でした。 std::cout

次の結果が得られました。

printf: 00:00:12.024
cout:   00:00:04.144

coutは常にprintfよりも高速ですか?おそらくそうではありません。特に古い実装ではそうではありません。ただし、新しい実装では、iostreamはstdioよりも高速である可能性があります。これは、実行時にフォーマット文字列を解析する代わりに、コンパイラがコンパイル時に、整数/浮動小数点数/オブジェクトを文字列に変換するために呼び出す必要のある関数を認識しているためです。

しかし、もっと重要なことは、printfとcoutの速度は実装に依存するため、OPによって記述された問題を簡単に説明することはできません。

于 2009-11-15T01:42:53.803 に答える
4

std :: cout / cinを使用する前に呼び出してみてくださいios::sync_with_stdio(false);。もちろん、プログラムでstdioとiostreamを混在させている場合を除きます。これは、悪いことです。

于 2009-11-15T02:05:04.693 に答える
1

プログラミングコンテストでの私の経験に基づくと、printfはcoutよりも高速です。

/が機能しているのに、cin/が原因で制限時間前にソリューションが成功しなかったときのことを何度も覚えています。coutprintfscanf

それに加えて、それはより多くの操作を行うので、(少なくとも私にとっては)coutより遅いのは正常のようです。printf

于 2009-11-15T01:52:52.190 に答える
0

OSが何らかの理由でプログラムの出力をキャッシュしている場合に備えて、いくつかendlのsまたはflushesを使用して、のバッファをフラッシュしてみてください。coutしかし、Charlesが言うように、この動作についての適切な説明はありません。したがって、それが役に立たない場合は、マシンに固有の問題である可能性があります。

于 2009-11-15T01:44:47.477 に答える
0

ostringstream最初にすべてのデータを書き込んでからcoutostringstream'sで使用する必要がありstr()ます。私は64ビットのWindows7を使用しており、Test1すでにかなり高速でしたTest2(マイレージは異なる場合があります)。を使用しostringstreamて最初に単一の文字列を作成し、次にそれを使用coutすると、実行時間が約3〜4分の1に短縮されます 。必ず。Test1#include <sstream>

つまり、置き換えます

void Test1()
{
    cout
        << "a:" << a << "\n"
        << "a:" << setfill('0') << setw(8) << a << "\n"
        << "b:" << b << "\n"
        << "c:" << c << "\n"
        << "d:" << d << "\n"
        << "e:" << e << "\n"
        << "f:" << setprecision(6) << f << "\n"
        << "g:" << setprecision(10) << g << endl;
}

と:

void Test1()
{
    ostringstream oss;
    oss
        << "a:" << a << "\n"
        << "a:" << setfill('0') << setw(8) << a << "\n"
        << "b:" << b << "\n"
        << "c:" << c << "\n"
        << "d:" << d << "\n"
        << "e:" << e << "\n"
        << "f:" << setprecision(6) << f << "\n"
        << "g:" << setprecision(10) << g << endl;
    cout << oss.str();
}

ostringstream呼び出すたびに画面に書き込もうとしない結果として、これが非常に高速になると思いoperator<<ますcout。また、経験を通じて、画面に書き込む回数を減らすと(一度にさらに書き込むことで)パフォーマンスが向上することにも気づきました(ここでも、マイレージは異なる場合があります)。

例えば、

void Foo1()
{
    for(int i = 0; i < 10000; ++i) {
        cout << "Foo1\n";
    }
}

void Foo2()
{
    std::string s;
    for(int i = 0; i < 10000; ++i) {
        s += "Foo2\n";
    }
    cout << s;
}

void Foo3()
{
    std::ostringstream oss;
    for(int i = 0; i < 10000; ++i) {
        oss << "Foo3\n";
    }
    cout << oss.str();
}

私の場合、Foo11,092ミリ秒、Foo2234ミリ秒、218ミリFoo3秒かかりました。 ostingstreamsはあなたの友達です。明らかに、Foo2とFoo3は(自明に)より多くのメモリを必要とします。これをCスタイルの関数と比較するには、バッファを試しsprintfてから、を使用してそのバッファを書き込みます。これにより、fprintfさらに効率が向上するはずですTest2(ただし、私にとっては、パフォーマンスがTest2約10%向上しただけです。実際coutprintfフード)。

コンパイラ:MinGW64(TDMとそのバンドルライブラリ)。

于 2014-02-04T17:17:45.210 に答える
0

を使用してみてくださいios::sync_with_stdio(false);。std :: cin/coutを使用する前に言及してください。stdioまたはiostreamを混合しませんが、iostream標準ストリームを対応する標準cストリームと同期します。例-iostreamのstd::cin/wcinはcstreamのstdinと同期されます

于 2015-04-18T08:53:53.987 に答える
-2

これがc++ストリームをcprintfと同じくらい速くするべきhaxです。私はそれをテストしたことはありませんが、うまくいくと思います。

ios_base::sync_with_stdio(0);
于 2009-11-15T02:04:37.487 に答える