28

ハッシュを計算するための小さなCプログラムがあります(ハッシュテーブル用)。コードはかなりきれいに見えるといいのですが、それとは関係のない何かが私を悩ませています。

約0.2〜0.3秒で約100万のハッシュを簡単に生成できます(/ usr / bin / timeでベンチマーク)。ただし、forループでそれらをprintf()すると、プログラムの速度が約5秒に低下します。

  1. どうしてこれなの?
  2. それを速くする方法は?mmapp()ing stdout多分?
  3. これに関してstdlibcはどのように設計されていますか?また、どのように改善できますか?
  4. カーネルはどのようにそれをより良くサポートできますか?ローカルの「ファイル」(ソケット、パイプなど)のスループットを本当に高速にするには、どのように変更する必要がありますか?

興味深く詳細な返信を楽しみにしています。ありがとう。

PS:これはコンパイラ構築ツールセット用なので、恥ずかしがらずに詳細を確認してください。それは問題自体とは何の関係もありませんが、私はその詳細が私に興味を持っていることを指摘したかっただけです。

補遺

私は解決策と説明のためのよりプログラム的なアプローチを探しています。確かに、配管はその仕事をしますが、私は「ユーザー」が何をするかを制御できません。

もちろん、私は現在テストを行っていますが、これは「通常のユーザー」では実行されません。しかし、それは単純なprintf()がプロセスを遅くするという事実を変えません。これは、私が最適なプログラムによる解決策を見つけようとしている問題です。


補遺-驚くべき結果

参照時間は、TTY内のプレーンなprintf()呼び出しの場合で、約4分20秒かかります。

/ dev / pts(Konsoleなど)でテストすると、出力が約5秒に高速化されます。

テストコードでsetbuffer()を使用して16384のサイズにすると、ほぼ同じ時間がかかります。8192でもほぼ同じで、約6秒です。

setbuffer()は、それを使用しても明らかに効果がありません。同じ時間がかかります(TTYでは約4分、PTSでは約5秒)。

驚くべきことに、TTY1でテストを開始してから、別のTTYに切り替えると、PTSの場合とまったく同じように約5秒かかります。

結論:カーネルは、アクセシビリティと使いやすさに関係する何かをします。は!

通常、アクティブな状態でTTYを見つめたり、別のTTYに切り替えたりしても、同じように遅くなります。


レッスン:出力を多用するプログラムを実行する場合は、別のTTYに切り替えてください。

4

9 に答える 9

34

バッファリングされていない出力は非常に遅いです。

デフォルトstdoutでは完全にバッファリングされていますが、端末に接続されてstdoutいる場合は、バッファリングされていないか、ライン バッファリングされています。

次のように、をstdout使用するためにバッファリングをオンにしてみてください。setvbuf()

char buffer[8192];

setvbuf(stdout, buffer, _IOFBF, sizeof(buffer));
于 2009-12-02T12:28:21.470 に答える
15

文字列をバッファーに保存し、最後に、またはバッファーがいっぱいになったときに定期的にファイル (またはコンソール) に出力することができます。

コンソールに出力する場合、スクロールは通常キラーです。

于 2009-12-02T12:06:37.077 に答える
9

コンソールにprintf()している場合、通常は非常に低速です。理由はわかりませんが、コンソールに出力された文字列がグラフィカルに表示されるまで戻らないと思います。さらに、stdoutにmmap()することはできません。

ファイルへの書き込みははるかに高速である必要があります(ただし、ハッシュの計算よりも桁違いに遅く、すべてのI / Oが低速です)。

于 2009-12-02T12:03:03.530 に答える
7

シェルの出力をコンソールからファイルにリダイレクトすることを試みることができます。これを使用すると、数ギガバイトのサイズのログをわずか数秒で作成できます。

于 2009-12-02T12:05:54.773 に答える
7
  1. I/O は、単純な計算に比べて常に低速です。システムは、コンポーネントを使用できるようになるまで待機する必要があります。次に、続行する前に応答を待つ必要があります。逆に、単純に計算している場合は、実際には RAM と CPU レジスタ間でデータを移動しているだけです。

  2. 私はこれをテストしていませんが、ハッシュを文字列に追加し、最後に文字列を出力する方が速い場合があります。ただし、C++ ではなく C を使用している場合、これは面倒なことになるかもしれません。

3 と 4 は私を超えています。

于 2009-12-02T12:06:16.380 に答える
4

私はずっと前にこのテクニックを使って明らかなはずの何かを発見しました。特にコンソールのI/Oが遅いだけでなく、10進数のフォーマットも高速ではありません。2進数の数値を大きなバッファーに入れ、それらをファイルに書き込むことができれば、はるかに高速であることがわかります。

その上、誰がそれらを読むつもりですか?誰もそれらすべてを読む必要がなければ、人間が読める形式でそれらすべてを印刷する意味はありません。

于 2009-12-02T13:26:18.260 に答える
4
  1. 構築時点ではなく、必要に応じて文字列を作成してみませんか? 1 秒間に 40 画面のデータを出力しても意味がありません。必要に応じて出力を作成し、最後の画面を完全に表示してから、必要に応じてユーザーがスクロールしないのはなぜですか?

  2. sprintf を使用して文字列に出力し、メモリ内のすべての結果を連結した文字列を作成して最後に出力しないのはなぜですか?

  3. sprintf に切り替えることで、フォーマット変換に費やされた時間とコンソールへの結果の表示に費やされた時間を明確に確認し、コードを適切に変更できます。

  4. コンソール出力は定義上遅く、ハッシュの作成は数バイトのメモリを操作するだけです。コンソール出力はオペレーティング システムの多くの層を通過する必要があり、スレッド/プロセスのロックなどを処理するコードがあり、最終的には 9600 ボー デバイスである可能性があるディスプレイ ドライバーに到達します。または大きなビットマップ表示の場合、画面のスクロールなどの単純な機能には、メガバイトのメモリの操作が含まれる場合があります。

于 2009-12-02T12:17:27.730 に答える
4

I/O は常に CPU 計算よりもはるかに遅いため、可能な限り高速な I/O に最初にすべての値を格納することができます。したがって、RAM が十分にある場合は RAM を使用し、そうでない場合は Files を使用しますが、RAM よりもはるかに低速です。

値の出力は、後で、または別のスレッドによって並行して実行できるようになりました。そのため、計算スレッドは、printf が返されるまで待機する必要がない場合があります。

于 2009-12-02T12:24:28.170 に答える
2

端末タイプはバッファリングされた出力操作を使用していると思われるため、printf を実行すると、分割マイクロ秒で出力されず、端末サブシステムのバッファ メモリに格納されます。

これは、スローダウンを引き起こす可能性のある他のものによって影響を受ける可能性があります。おそらく、プログラム以外でメモリを集中的に使用する操作が実行されている可能性があります。要するに、ページング、スワッピング、別のプロセスによる大量の I/O、使用されるメモリの構成、おそらくメモリのアップグレードなど、すべて同時に発生する可能性のあることが多すぎます。

文字列を一定の制限に達するまで連結し、制限に達すると、すべてを一度に書き出す方がよい場合があります。または、pthreads を使用して目的のプロセス実行を実行することもできます。

編集: 2,3 に関しては、私を超えています。4 の場合、私は Sun に精通していませんが、Solaris のことは知っていて、いじりました。仮想 tty を使用するカーネル オプションがあるかもしれません。 . そのため、これについての私の記憶はあまりよくないかもしれません。

user@host:/usr/src/linux $ make; make menuconfig **X からの場合は kconfig **

これにより、カーネル メニューが起動されます。デバイス サブツリーの下にあるビデオ設定セクションを参照してください。

編集済み: しかし、ファイルをprocファイルシステムに追加することでカーネルに加える調整があります(そのようなものが存在する場合)、またはおそらくカーネルに渡されたスイッチ、このようなもの(これは想像上のものであり、実際にそれを意味するものではありませんあります)、fastio

これがお役に立てば幸いです。よろしくお願いします、トム。

于 2009-12-02T12:40:43.063 に答える