テキストエディタで実行できる小さな論理プログラムの場合、トレースにはクラシックを使用しますSystem.out.println()
。
多数の反復のブロックでそれを使用することがどれほど苛立たしいことか、皆さんご存知だと思います。なんでこんなに遅いの?その背後にある理由は何ですか?
テキストエディタで実行できる小さな論理プログラムの場合、トレースにはクラシックを使用しますSystem.out.println()
。
多数の反復のブロックでそれを使用することがどれほど苛立たしいことか、皆さんご存知だと思います。なんでこんなに遅いの?その背後にある理由は何ですか?
これは、JVMとは何の関係もありません。画面にテキストを印刷するには、OSが文字を描画したり、特にスクロールしたりするのに多くの作業が必要になります。System.outをファイルにリダイレクトすると、はるかに高速になります。
これはOSに大きく依存します。たとえば、Windowsでは、コンソールへの書き込みはブロック操作であり、速度も遅いため、コンソールに大量のデータを書き込むと、アプリケーションの速度が低下(またはブロック)します。UNIXタイプのOSでは、コンソールへの書き込みはバッファリングされるため、アプリはブロックを解除し続けることができ、コンソールは可能な限り追いつきます。
ええ、コンソールへの書き込みには膨大なオーバーヘッドがあります。ファイルやソケットへの書き込みに必要なものよりはるかに大きい。また、多数のスレッドがある場合、それらはすべて同じロックで競合しています。System.out.println以外のものを使用してトレースすることをお勧めします。
これは、JavaおよびJVMとは関係ありませんが、コンソール端末とは関係があります。ほとんどのOSでは、コンソール出力への書き込みが遅いことを知っています。
バッファリングは非常に役立ちます。これを試して:
System.setOut( new PrintStream(new BufferedOutputStream(System.out)) );
ただし、注意してください。出力が徐々に表示されることはありませんが、すべてが一瞬で表示されます。これは素晴らしいことですが、デバッグに使用していて、プログラムが終了する前にクラッシュした場合、状況によっては、クラッシュの直前にテキストが印刷されない可能性があります。これは、クラッシュ前にバッファがフラッシュされなかったためです。それは印刷されましたが、それはまだバッファにあり、あなたがそれを見ることができるコンソールにそれを出しませんでした。不可解なデバッグセッションで、これが私に起こったことを覚えています。時々明示的にフラッシュして、確実に表示されるようにすることをお勧めします。
System.out.flush();
ターミナルへの書き込みについて私が気付いた興味深いことの1つ(少なくともWindowsでは)。ウィンドウが最小化されている場合、実際にははるかに高速に実行されますか?これは、描画とスクロールに関するMichaelBorgwardtの回答と確実に密接に関連しています。実際、速度低下に気付くのに十分なログを記録している場合は、ファイルに書き込む方がよいでしょう。
これはあなたの質問に直接答えないように見えるかもしれませんが、トレースに System.out を使用しないことをお勧めします (アプリの進歩を確認するためだけにデバッグのようなものを意味する場合)。
デバッグ用の System.out にはいくつかの問題があります。
アプリが終了すると、コンソールを閉じるとログが失われます
アプリが正常に動作するようになったら、これらのステートメントを削除する必要があります (またはコメントしてください)。後でそれらを再度アクティブにしたい場合は、コメントを解除/再度コメントする必要があります...面倒です
代わりに log4j を使用し、ログ ファイルを "監視" することをお勧めします。どちらも、tail コマンドを使用します。Windows 用の Tailもあります。LogWatcherのような Eclipse プラグインを使用します。
一部の端末は、他の端末よりも高速です。これは、1 つのオペレーティング システム内でも異なる場合があります。
速度が遅いのは、改行またはフラッシュのたびに発生する大量のJava-Native遷移が原因です。反復に多くのステップが必要な場合、System.out.println()はあまり役に立ちません。反復ステップ自体がそれほど重要でない場合は、10または100ステップごとにのみSystem.out.println()を呼び出すことができます。System.outをBufferedOutputStreamにラップすることもできます。そしてもちろん、ExecutorServiceを介して印刷を非同期化するオプションは常にあります。