c 標準出力 出力を/ dev/nullにリダイレクトしても、printfにはまだコストがかかりますか?




標準エラー出力 捨てる (4)

かなり

プログラムの標準出力を /dev/null にリダイレクトしても、 printf(3) を呼び出してもすべての引数が評価され、文字列フォーマット処理は write(2) 呼び出す前に行われます。プロセスの標準出力へ。 カーネルレベルでは、データはディスクに書き込まれませんが、特殊なデバイス /dev/null 関連付けられたハンドラによって破棄され /dev/null

したがって、せいぜい、引数を評価して printfprintf 背後にある文字列フォーマットジョブ、および実際にデータを書き込むための少なくとも1つのシステムコールに渡すオーバーヘッドを回避または回避しないでください。 /dev/null まあ、それはLinux上で本当の違いです。 実装は単にあなたが書きたかったバイト数( write(2) への呼び出しの3番目の引数で指定される)を返し、それ以外はすべて無視します( この答えを 見てください)。 書き込んでいるデータの量、およびターゲットデバイス(ディスクまたは端末)の速度によっては、パフォーマンスの違いが大きく異なる場合があります。 組み込みシステムでは、一般的に言って、 /dev/null リダイレクトすることでディスクへの書き込みを遮断すると、重要でない量の書き込みデータのためにかなりのシステムリソースを節約できます。

理論的には、プログラムは /dev/null を検出し、準拠している標準(ISO CおよびPOSIX)の制限内でいくつかの最適化を実行できますが、一般的な実装の一般的な理解に基づいています。任意のUnixまたはLinuxシステム

POSIX標準では、 printf(3) 呼び出しに対して標準出力への書き込みが義務付けられているため、関連するファイル記述子によっては write(2) 呼び出しを抑制することは標準に準拠していません。 POSIX要件の詳細については、 Damonの回答を 読むことができます。 ああ、そして簡単なメモ:すべてのLinuxディストリビューションは、そうであるとは 認定さ れていませんが、実質的にPOSIXに準拠しています。

printf 完全に置き換えると、 printf("%d%n", a++, &b) 副作用が発生することがあります。 プログラムの実行環境に応じて出力を抑制する必要がある場合は、グローバルフラグを設定し、印刷前にフラグをチェックするためにprintfをラップすることを検討してください。パフォーマンスの低下が見られるほどプログラムを遅くするつもりはありません。つまり、単一の条件チェックは、 printf を呼び出してすべての文字列フォーマットを実行するよりも はるかに 高速です。

たくさんの印刷メッセージを含むデーモンがあります。 私たちは弱いCPUと他の制約ハードウェアを持つ組込み機器に取り組んでいるので、私たちの最終版ではprintfメッセージのどんな種類のコスト(IO、CPUなど)も最小にしたいです。 (ユーザーはコンソールを持っていません)

私のチームメイトと私は意見の相違があります。 彼は、すべてを/ dev / nullにリダイレクトすることができると考えています。 IOはかかりませんので、影響は最小限に抑えられます。 しかし、それでもCPUのコストがかかると思いますし、printf用のマクロを定義したほうがよいので、 "printf"を書き換えることができます(おそらくreturn)。

だから私は誰が正しいかについていくつかの意見が必要です。 Linuxはprintfを最適化するのに十分賢いでしょうか? 私は本当にそれを疑います。


ガイドラインとしてprintf()ソースを使用して、printf()をラップし、noprintフラグが設定されている場合は直ちに戻る独自のものを作成してください。 これのマイナス面は、実際に印刷するときにフォーマット文字列を2回解析しなければならないため、より多くのリソースを消費することです。 しかし、印刷していないときには無視できるリソースを使用します。 printf()内の基本的な呼び出しが新しいバージョンのstdioライブラリで変更される可能性があるため、単純にprintf()を置き換えることはできません。

void printf2(const char * formattring、...);


printf 関数 stdout 書き込みます。 /dev/null 最適化には準拠していません。 したがって、フォーマット文字列を解析して必要な引数を評価するというオーバーヘッドがあり、少なくとも1つのsyscallがあります。さらに、カーネルアドレス空間にバッファをコピーします(syscallのコストと比較すると無視できます)。 。

この答えはPOSIXの特定のドキュメントに基づいています。

システムインタフェース
dprintf、fprintf、printf、snprintf、sprintf - フォーマットされた出力を印刷する

fprintf()関数は、指定された出力ストリームに出力を配置します。 printf()関数は標準出力ストリームstdoutに出力を配置します。 sprintf()関数は、* sで始まる連続したバイトに、出力とそれに続くヌルバイト '\ 0'を配置します。 十分なスペースがあることを確認するのはユーザーの責任です。

基本定義
する
POSIX.1-2017に準拠する実装の場合、必須の機能または動作について説明します。 アプリケーションは、機能または動作の存在に頼ることができます。


printf 関数は stdout 書き込みます。 stdout 接続されているファイルディスクリプタが /dev/null リダイレクトされている場合、どこにも出力は書き込まれません(しかし、それでも書き込まれます)が、 printf 自体の呼び出しとそれによるフォーマットは行われます。





dev-null