12

私は今でもコンソール出力を使用して、自分のコードで何が起こっているかを把握しています。これは少し古い方法かもしれませんが、標準出力をログ ファイルなどに「パイプ」するためにもこれを使用します。

ただし、何らかの理由でコンソールへの出力が遅くなることが判明しました。コンソール ウィンドウへの fprintf() がブロックしているように見える理由を誰かが説明できるかどうか疑問に思っていました。

これまでに行ったこと/診断したこと:

  1. 必要な時間を簡単に測定しました fprintf(stdout,"quick fprintf\n"); :0.82ms(平均)。vsprintf_s(...)これは、同じ出力をわずか数マイクロ秒で文字列に書き込むため、長すぎると考えられています。したがって、コンソールに固有のブロッキングが必要です。

  2. ブロッキングから逃れるためにvsprintf_s(...)、出力を fifo に似たデータ構造にコピーするために使用しました。データ構造は、クリティカル セクション オブジェクトによって保護されます。次に、別のスレッドが、キューに入れられた出力をコンソールに出力することにより、データ構造のキューを解除します。

  3. パイプ サービスの導入によって得られたもう 1 つの改善点。私のプログラムの出力 (コンソール ウィンドウに表示されるはずです) は、次のようになります。

    • Avsprintf_s(...)は、出力を単純な文字列にフォーマットします。
    • 文字列は、FIFO に似たデータ構造 (リンクされたリスト構造など) のキューに入れられます。このデータ構造は、クリティカル セクション オブジェクトによって保護されています。
    • 2 番目のスレッドは、出力文字列を名前付きパイプに送信して、データ構造をデキューします。
    • 2 番目のプロセスは、名前付きパイプを読み取り、文字列を fifo に似たデータ構造に再び配置します。これは、読み取りをコンソールへのブロック出力から遠ざけるために必要です。読み取りプロセスは、名前付きパイプの読み取りが高速で、パイプ バッファーのフィル レベルを継続的に監視します。
    • その 2 番目のプロセスの 2 番目のスレッドは、最終的にデータ構造fprintf(stdout,...)をコンソールにデキューします。

したがって、それぞれ少なくとも 2 つのスレッドを持つ 2 つのプロセスがあり、それらの間に名前付きパイプがあり、パイプの両側に fifo のようなデータ構造があり、パイプ バッファーがいっぱいになった場合のブロックを回避します。

これは、コンソール出力が「ノンブロッキング」であることを確認するための多くのものです。しかし、結果はそれほど悪くありません。私のメイン プログラムは、わずか数マイクロ秒で複雑な fprintf(stdout,...) を書き込むことができます。

多分私は以前に尋ねるべきだった: ノンブロッキングコンソール出力を持つ他の (より簡単な!) 方法はありますか?

4

1 に答える 1

13

タイミングの問題は、コンソールがデフォルトで行バッファリングされているという事実に関係していると思います。これは、文字を書き込むたび'\n'に、出力バッファー全体がコンソールに送信されることを意味します。これはかなりコストのかかる操作です。これは、出力にすぐに表示される行に対して支払う価格です。

このデフォルトの動作は、バッファリング戦略をフル バッファリングに変更することで変更できます。結果として、出力はバッファのサイズと等しいチャンクでコンソールに送信されますが、個々の操作はより速く完了します。

最初にコンソールに書き込む前に、次の呼び出しを行います。

char buf[10000];
setvbuf(stdout, buf, _IOFBF, sizeof(buf));

個々の書き込みのタイミングは改善されるはずですが、出力はすぐにはコンソールに表示されません。これはデバッグにはあまり役に立ちませんが、タイミングは改善されます。一定の時間間隔で (たとえば 1 秒ごとに)呼び出すスレッドを設定する場合fflush(stdout)、個々の書き込みのパフォーマンスと、プログラムが出力を書き込んでから実際に表示されるまでの遅延との間で妥当なバランスを取る必要があります。コンソール。

于 2012-07-19T10:32:09.607 に答える