48

私は、 C や C++ などの低レベル言語で大規模なライブラリ ( GLibBoostなど) を使用することに気が進まない心理的な傾向があります。私の考えでは、次のように考えています。

このライブラリには何千時間もの工数が費やされており、この言語について私よりも多くのことを知っている人々によって作成されています。それらの作成者とファンは、ライブラリが高速で信頼性が高く、機能が非常に便利であると言っています。

しかし、くそー、そのライブラリのすべての関数を使用するつもりはありません。大きすぎて、おそらく何年にもわたって肥大化しています。それは私のプログラムがドラッグする必要がある別のボールとチェーンです。

Torvaldsの暴言(物議をかもしていますが) も、私の心を落ち着かせるものではありません。

私の考えに何か根拠はありますか、それとも私は単に理不尽で無知なだけなのでしょうか? 大きなライブラリの 1 つまたは 2 つの機能しか使用しない場合でも、そのライブラリにリンクすることで、実行時のパフォーマンス オーバーヘッドが発生しますか?

特定のライブラリが何であるかにもよると確信していますが、大規模なライブラリが技術レベルで本質的に非効率性をもたらすかどうかを知りたいと思っています。

自分が正しいかどうかを判断するための技術的な知識を持っていないとき、私はこれについて取りつかれ、つぶやき、心配するのにうんざりしています。

私を窮地から救い出してください!

4

17 に答える 17

30

大きなライブラリの 1 つまたは 2 つの機能しか使用しない場合でも、そのライブラリにリンクすることで、実行時のパフォーマンス オーバーヘッドが発生しますか?

一般的に、いいえ。

問題のライブラリに位置に依存しないコードが多くない場合、動的リンカが要求されたときにライブラリで再配置を実行する間、起動コストが発生します。通常、これはプログラムの起動の一部です。それ以上の実行時のパフォーマンスへの影響はありません。

リンカーは、ビルド時に静的にリンクされたライブラリから「デッド コード」を削除することにも優れているため、使用する静的ライブラリのサイズ オーバーヘッドは最小限に抑えられます。パフォーマンスはそれにさえ入りません。

率直に言って、あなたは間違ったことを心配しています。

于 2010-02-11T20:29:33.293 に答える
25

GLib についてコメントすることはできませんが、Boost のコードの多くはヘッダーのみであり、ユーザーが使用した分だけ支払うという C++ の原則を考慮すると、ライブラリは非常に効率的であることを覚えておいてください。それらに対してリンクする必要があるライブラリがいくつかあります (正規表現、ファイルシステムが思い浮かびます) が、それらは別個のライブラリです。Boost を使用すると、大規模なモノリシック ライブラリに対してリンクするのではなく、使用する小さなコンポーネントに対してのみリンクします。

もちろん、他の質問は - 代替手段は何ですか? 必要なときにBoostにある機能を自分で実装したいですか? 多くの非常に有能な人々がこのコードに取り組み、多数のコンパイラで動作し、依然として効率的であることを確認したことを考えると、これは単純な作業ではない可能性があります。さらに、少なくともある程度は車輪の再発明を行っています。私見では、この時間をより生産的に過ごすことができます。

于 2010-02-11T20:30:43.887 に答える
13

Boost は大きなライブラリではありません。

多くの小さなライブラリのコレクションです。それらのほとんどは非常に小さいため、1 つまたは 2 つのヘッダーに含まれています。Usingは、コードにドラッグしたり、コードに挿入したりboost::noncopyableしません。それらは異なるライブラリです。それらは、同じライブラリ コレクションの一部として配布されているだけです。ただし、使用した分だけお支払いいただきます。boost::regexboost::thread

しかし、Boost がその 1 つではなくても、大きなライブラリが存在するため、一般的に言えば、次のようになります。

私の考えに何か根拠はありますか、それとも私は単に理不尽で無知なだけなのでしょうか? 大きなライブラリの 1 つまたは 2 つの機能しか使用しない場合でも、そのライブラリにリンクすることで、実行時のパフォーマンス オーバーヘッドが発生しますか?

多かれ少なかれ根拠はありません。自分でテストできます。

小さな C++ プログラムを作成してコンパイルします。ここで、呼び出されることはありませんが、定義されている新しい関数を追加します。プログラムを再度コンパイルします。最適化が有効になっていると仮定すると、未使用であるため、リンカーによって取り除かれます。したがって、追加の未使用コードを含めるコストはゼロです。

もちろん例外もあります。コードがグローバル オブジェクトをインスタンス化する場合、それらは削除されない可能性があります (iostreamヘッダーを含めると実行可能ファイルのサイズが増加するのはそのためです)。追加されたコードを使用しない限り、プログラムのサイズ、パフォーマンス、またはメモリ使用量に影響します。

もう 1 つの例外は、.dll または .so に動的にリンクする場合、ライブラリ全体を配布する必要があるため、未使用のコードを取り除くことができないことです。ただし、実行可能ファイルに静的にコンパイルされたライブラリ (静的ライブラリ (.lib または .a) またはインクルードされたヘッダー ファイルとしてのいずれか) は、通常、リンカーによって削除され、未使用のシンボルが削除されます。

于 2010-02-11T22:29:37.820 に答える
11

大規模なライブラリは、コードパフォーマンスの観点から次のようになります。

  • ランタイムバイナリがある場合は、より多くのメモリを占有boostします(のほとんどの部分はランタイムバイナリを必要とせず、「ヘッダーのみ」です)。OSはライブラリの実際に使用されている部分のみをRAMにロードしますが、ロードされるものの粒度はページサイズに等しいため(ただし、私のシステムでは4 Kbのみ)、必要以上にロードできます。
  • 繰り返しになりますが、ランタイムバイナリが必要な場合は、ダイナミックリンカによるロードに時間がかかります。プログラムがロードされるたびに、ダイナミックリンカは、外部ライブラリに含める必要のある各関数を、メモリ内の実際のアドレスと一致させる必要があります。少し時間がかかりますが、少しだけです(ただし、デスクトップ環境の起動など、多くのプログラムをロードする規模では重要ですが、選択の余地はありません)。

    そして、はい、共有(ダイナミックリンク)ライブラリの外部関数を呼び出すたびに、実行時に1つの追加のジャンプと2つのポインター調整が必要になります

開発者のパフォーマンスの観点から:

  • 外部依存関係を追加します。あなたは他の誰かに依存するでしょう。そのライブラリの無料ソフトウェアであっても、それを変更するには追加の費用が必要になります。非常に低レベルのプログラム(私はOSカーネルについて話している)の開発者の中には、誰かに頼ることを嫌う人もいます。それが彼らの専門的な特典です。したがって、暴言。

    ただし、それはメリットと見なすことができます。他の人が慣れている場合boost、彼らはあなたのプログラムでおなじみの概念や用語を見つけ、それをより効果的に理解して修正するでしょう。

  • より大きなライブラリには通常、理解するのに時間がかかるライブラリ固有の概念が含まれています。Qtを検討してください。信号とスロット、およびmoc関連するインフラストラクチャが含まれています。Qt全体のサイズと比較して、それらを学習するのにかかる時間はごくわずかです。しかし、そのような大きなライブラリのごく一部を使用する場合、それは問題になる可能性があります。

于 2010-02-11T20:42:42.640 に答える
5

余分なコードが魔法のようにプロセッサの動作を遅くすることはありません。ほんの少しのメモリを占有してそこに座っているだけです。

静的にリンクしていて、リンカがまったく合理的である場合は、実際に使用する関数のみが含まれます。

于 2010-02-11T20:27:34.413 に答える
4

フレームワーク、ライブラリセット、およびいくつかの種類の開発ツールで私が好きな用語は、プラットフォームテクノロジです。プラットフォームテクノロジーには、コードサイズとパフォーマンスへの影響を超えるコストがあります。

  1. プロジェクト自体がライブラリまたはフレームワークとして使用されることを意図している場合は、ライブラリを使用する開発者にプラットフォームテクノロジの選択をプッシュすることになります。

  2. プロジェクトをソース形式で配布すると、エンドユーザーにプラットフォームテクノロジの選択を押し付けることになります。

  3. 選択したすべてのフレームワークとライブラリを静的にリンクしないと、ライブラリのバージョン管理の問題でエンドユーザーに負担がかかる可能性があります。

  4. コンパイル時間は開発者の生産性に影響します。インクリメンタルリンク、プリコンパイル済みヘッダー、適切なヘッダー依存関係管理などは、コンパイル時間を管理するのに役立ちますが、一部のプラットフォームテクノロジによって導入される大量のインラインコードに関連するコンパイラパフォーマンスの問題を排除することはできません。

  5. ソースとして配布されるプロジェクトの場合、コンパイル時間はプロジェクトのエンドユーザーに影響します。

  6. 多くのプラットフォームテクノロジには、独自の開発環境要件があります。これらの要件は蓄積される可能性があり、プロジェクトの新しい開発者がコンパイルとデバッグを可能にするために必要な環境を複製できるようにすることは困難で時間がかかります。

  7. いくつかのプラットフォームテクノロジーを実際に使用すると、プロジェクトの新しいプログラミング言語が作成されます。これにより、新しい開発者が貢献することが難しくなります。

すべてのプロジェクトにはプラットフォームテクノロジの依存関係がありますが、多くのプロジェクトでは、これらの依存関係を最小限に抑えることには真のメリットがあります。

于 2010-02-12T02:26:59.513 に答える
3

他の人が言ったように、動的ライブラリを追加するとオーバーヘッドが発生します。ライブラリが最初にロードされるとき、再配置を実行する必要がありますが、ライブラリが正しくコンパイルされていれば、これはわずかなコストです。検索する必要があるライブラリの数が増えるため、個々のシンボルを検索するコストも増加します。

別の動的ライブラリを追加する場合のメモリのコストは、実際に使用するライブラリの量に大きく依存します。コードのページは、何かが実行されるまでディスクからロードされません。ただし、ライブラリ ファイルに組み込まれているヘッダー、シンボル テーブル、ハッシュ テーブルなどの他のデータは読み込まれ、これらは通常、ライブラリのサイズに比例します。

glibc の主な貢献者である Ulrich Drepper による、動的ライブラリーのプロセスとオーバーヘッドについて説明した優れたドキュメントがあります。

于 2010-02-11T23:13:45.657 に答える
3

大きいからといって、本質的に遅いという意味ではありません。他のいくつかの回答とは対照的に、ヘッダーに完全に保存されたライブラリとオブジェクトファイルに保存されたライブラリの間に本質的な違いはありません。

ヘッダーのみのライブラリは、間接的な利点があります。ほとんどのテンプレート ベースのライブラリはヘッダーのみにする必要があり (または、とにかく多くのコードが最終的にヘッダーになります)、テンプレートには最適化の機会がたくさんあります。典型的なオブジェクト ファイル ライブラリのコードをすべてヘッダーに移動しても、通常は多くの良い効果が得られるわけではありません (コードが肥大化する可能性もあります)。

特定のライブラリの実際の答えは、通常、その全体的な構造によって異なります。「Boost」を巨大なものと考えるのは簡単です。実際、これはライブラリの膨大なコレクションであり、そのほとんどは個別に非常に小さいものです。個々のライブラリはさまざまな人によって、さまざまな手法や目標などで書かれているため、Boost 全体について (意味のあることを言っても) あまり多くを語ることはできません。そのうちのいくつか (たとえば、Format、Assign) は、ほとんどすべてよりも実際に遅いです。あなたは自分でやる可能性が非常に高いでしょう。他のもの (Pool など) は、自分でできることを提供しますが、少なくともマイナーな速度向上を得るために、おそらくしないでしょう。一部のユーザー (uBlas など) は、強力なテンプレート マジックを使用して、他のどのツールよりも高速に実行できますが、私たちのごく一部は、自分で達成したいと考えています。

もちろん、実際には個々に大きなライブラリであるライブラリがかなりあります。多くの場合、これらは実際に自分で作成するよりも遅くなります。特に、それらの多く (ほとんど?) は、自分で作成する可能性のあるほとんどのものよりもはるかに一般的であるように努めています。それが必ずしもコードの低速化につながるわけではありませんが、その傾向が強いことは間違いありません。他の多くのコードと同様に、商業的にライブラリを開発している場合、顧客は速度のサイズなどよりも機能に関心を持つ傾向があります。

一部のライブラリは、多くのスペース、コード (そして多くの場合、少なくとも少しの時間) を、まったく気にしない問題を解決するために費やしています。たとえば、数年前、私は画像処理ライブラリを使用しました。200 以上の画像フォーマットのサポートは非​​常に印象的でした (ある意味では実際にそうでした) が、私はそれを使用して約 12 以上のフォーマットを処理したことがなかったと確信しています (そして、おそらくその半分だけをサポートすることで得られた可能性があります)。たくさんの)。OTOH、それでもかなり速かったです。少数の市場をサポートすることは、コードが実際に遅くなる点に市場を制限した可能性があります (たとえば、IJG よりも JPEG の処理が高速でした)。

于 2010-02-11T21:29:52.980 に答える
3

There may be a small overhead when loading these libraries if they're dynamically linked. This will typically be a tiny, tiny fraction of the time your program spends running.

However there will be no overhead once everything is loaded.

If you don't want to use all of boost, then don't. It's modular, so you can use the parts you want and ignore the rest.

于 2010-02-11T20:26:56.737 に答える
2
  1. 一般に、パフォーマンスの問題に対処することは、彼らを楽しませることではありません。なぜなら、そうするは、それが問題であると推測することだからです。 「時期尚早の最適化」の背後にある概念。パフォーマンスの問題と関係があるのは、問題が発生する前ではなく、問題が発生したときに診断することです。問題は、あなたが推測したものではありません。拡張された例を次に示します。

  2. これをかなり行うと、コードであろうとライブラリであろうと、パフォーマンスの問題を引き起こす傾向がある設計アプローチを認識するようになります。(ライブラリには確かにパフォーマンス上の問題がある可能性があります。) それを学び、それをプロジェクトに適用すると、ある意味で時期尚早に最適化されますが、問題を回避するという望ましい効果があります。あなたがおそらく学ぶであろうことを要約すると、抽象化の層が多すぎることと、誇張されたクラス階層 (特に通知スタイルの更新でいっぱいのもの) が、パフォーマンスの問題の原因であることが非常に多いということです。

同時に、サードパーティのライブラリなどに関するあなたの注意事項を共有します。サードパーティのパッケージが「相乗効果」のために「活用」されたプロジェクトに何度も取り組んできましたが、Microsoft が OS の変更を行ったために、ベンダーが煙を上げたり、製品を放棄したり、時代遅れになったりしました。その後、サードパーティのパッケージに大きく依存していた私たちの製品が機能しなくなり、元のプログラマーがいなくなって久しい間、私たちの側で多額の出費が必要になりました。

于 2010-02-12T01:52:43.550 に答える
2

リンカーの動作に依存します。一部のリンカは怠惰で、すべてのコードをライブラリに含めます。より効率的なリンカーは、ライブラリから必要なコードのみを抽出します。どちらのタイプも経験あります。

小さいライブラリは、どちらのタイプのリンカーでも心配する必要はありません。小さなライブラリの最悪のケースは、少量の未使用コードです。小さなライブラリが多数あると、ビルド時間が長くなる可能性があります。トレードオフは、ビルド時間とコードスペースです。

リンカーの興味深いテストは、古典的なHello Worldプログラムです。

#include <stdio>
#include <stdlib>
int main(void)
{
  printf("Hello World\n");
  return EXIT_SUCCESS;
}

関数には、必要となる可能printf性のあるすべての書式設定のために、多くの依存関係があります。怠惰ではあるが高速なリンカーには、すべてのシンボルを解決するための「標準ライブラリ」が含まれている場合があります。より効率的なライブラリには、とその依存関係のみが含まれます。これにより、リンカーが遅くなります。printf

上記のプログラムは、次を使用してこのプログラムと比較できますputs

#include <stdio>
#include <stdlib>
int main(void)
{
  puts("Hello World\n");
  return EXIT_SUCCESS;
}

一般に、putsバージョンはバージョンよりも小さくする必要があります。これは、書式設定の必要がないprintfため、依存関係が少ないためです。putsレイジー リンカーは、プログラムと同じサイズのコードを生成しますprintf

要約すると、ライブラリ サイズの決定には、リンカーへの依存度が高くなります。具体的には、リンカーの効率。疑わしい場合、多くの小さなライブラリはリンカの効率にあまり依存しませんが、ビルド プロセスはより複雑で遅くなります。

于 2010-02-11T23:25:45.940 に答える
1

「別のボールとチェーン」。本当に?

それとも、最初からアプリケーションを可能にする安定した信頼できるプラットフォームですか?

一部の人々は、他のプロジェクトに使用し、本当に信頼しているため、「大きすぎて... 肥大化した」ライブラリが好きかもしれないと考えてください。

実際、明らかに「大きすぎて肥大化した」ライブラリの使用を避けたために、ソフトウェアをいじることを拒否する可能性があります。

于 2010-02-11T20:32:03.993 に答える
1

技術的には、答えはイエスです。ただし、これらの非効率性が実際に重要になることはめったにありませんここでは、C、C++、D などの静的にコンパイルされた言語を想定しています。

実行可能ファイルが最新の OS のメモリにロードされると、アドレス空間が単純にマップされます。これは、実行可能ファイルがどれほど大きくても、使用されていないページ サイズのコード ブロック全体が存在する場合、それらが物理メモリに触れることは決してないことを意味します。ただし、アドレス空間を浪費することになり、32 ビット システムではこれが問題になる場合があります。

ライブラリにリンクするとき、通常、優れたリンカは使用しない余分なものを破棄しますが、特にテンプレートのインスタンス化の場合、これが常に発生するとは限りません。したがって、バイナリは厳密に必要なサイズよりも少し大きくなる可能性があります。

使用しないコードが使用するコードと頻繁にインターリーブされている場合、CPU キャッシュ内のスペースが無駄になる可能性があります。ただし、キャッシュ ラインは小さいため (通常は 64 バイト)、これが実際に重要なレベルで発生することはめったにありません。

于 2010-02-11T20:32:41.573 に答える
0

fwiw、私はMicrosoft Windowsで作業しており、Windowsを構築するときもそうです。SIZE用にコンパイルされたビルドは、ページフォールトヒットが少ないため、 SPEED用にコンパイルされたビルドよりも高速です。

于 2010-02-11T22:51:58.250 に答える
0

あなたの目標が何であるかを自問してください。それは今日のミッドエンドワークステーションですか?問題ありません。それは古いハードウェアなのか、それとも限られた組み込みシステムなのか、そうかもしれません。

以前の投稿者が言ったように、そこにコードがあるだけではパフォーマンスにそれほどコストはかかりません(キャッシュの局所性が低下し、読み込み時間が長くなる可能性があります)。

于 2010-02-11T20:59:33.270 に答える
0

FFTW と ATLAS は 2 つの非常に大きなライブラリです。奇妙なことに、それらは世界最速のソフトウェア、スーパーコンピューター上で実行するように最適化されたアプリケーションで大きな役割を果たしています。いいえ、大規模なライブラリを使用してもコードが遅くなることはありません。特に代替手段として FFT または BLAS ルーチンを自分で実装している場合はそうです。

于 2010-02-12T03:38:46.263 に答える
-11

特にブーストに関しては、心配するのは当然です。それを書いている人が無能だからではなく、2 つの問題が原因です。

  1. テンプレートは本質的に肥大化したコードです。これは 10 年前ほどは問題ではありませんでしたが、現在では CPU はメモリ アクセスよりもはるかに高速であり、この傾向は続いています。テンプレートは廃止された機能であると言えます。

通常はある程度実用的なユーザーコードにとってはそれほど悪くはありませんが、多くのライブラリでは、すべてが他のテンプレートまたは複数のアイテムのテンプレートに関して定義されています (指数関数的なテンプレートコードの爆発を意味します)。

単に iostream を追加するだけで、コードに約 3 MB (!!!) 追加されます。次に、いくつかのブーストナンセンスを追加すると、特に奇妙なデータ構造をいくつか単純に宣言すると、30 MB のコードになります。

さらに悪いことに、これを簡単にプロファイリングすることさえできません。私が書いたコードとテンプレート ライブラリからのコードの違いは劇的ですが、より単純なアプローチでは、単純なテストではうまくいかないと思うかもしれません。アプリ。

  1. 複雑。Boost 内のものを見ると、それらはすべてコードを非常に複雑にするものです。スマート ポインター、ファンクター、あらゆる種類の複雑なものなどです。さて、このようなものを使用することが決して良い考えではないとは言いませんが、ほとんどの場合、何らかの大きなコストがかかります. 特に正確に理解していない場合は、正確に、それが何をしているのかを意味します。

しかし、人々はそれを絶賛し、それが「デザイン」に関係しているふりをするので、めったに使用されるべきではない非常に特殊なツールだけでなく、すべてを行うべき方法であるという印象を受けます. もしそうなら。

于 2010-02-11T21:30:18.320 に答える