ライブラリを使用する際に効率性を高めるのが難しいのはなぜですか?

datascience.stackexchange https://datascience.stackexchange.com/questions/138

  •  16-10-2019
  •  | 
  •  

質問

小規模なデータベース処理は、Python/Perl/... で簡単に取り組むことができます。スクリプト。言語自体のライブラリやユーティリティを使用します。ただし、パフォーマンスのことになると、C/C++/低レベル言語に手が伸びてしまう傾向があります。ニーズに合わせてコードを調整できることが、メモリ管理、並列処理、ディスク アクセス、または (C/C++ レベルのアセンブリ構造を介した) 低レベルの最適化に関するものであっても、これらの言語を BigData にとって非常に魅力的なものにしているようです。

もちろん、このような一連の利点はコストなしには得られません。コードを書いたり、場合によっては 車輪の再発明, 、かなり高価/面倒な場合があります。利用可能なライブラリはたくさんありますが、人々は必要なときはいつでも自分でコードを書く傾向があります。 付与 パフォーマンス。何 無効にする 大規模なデータベースの処理中にライブラリを使用するとパフォーマンスが低下しますか?

たとえば、継続的に Web ページをクロールし、収集されたデータを解析する企業について考えてみましょう。スライディング ウィンドウごとに、抽出されたデータに対して異なるデータ マイニング アルゴリズムが実行されます。なぜ開発者は利用可能なライブラリ/フレームワーク (クローリング、テキスト処理、データ マイニングなど) の使用をやめるのでしょうか?すでに実装されているものを使用すると、プロセス全体のコーディングの負担が軽減されるだけでなく、時間を大幅に節約できます。

一発で:

  • 自分でコードを書く理由 保証 パフォーマンスの?
  • それはなぜです リスキーな 必要な場合にフレームワーク/ライブラリに依存する 保証します ハイパフォーマンス?
役に立ちましたか?

解決

自分自身でゲームの書き換えを何度も繰り返してきました(そして今も続けています)、私の即座の反応は次のとおりでした。 適応力.

フレームワークとライブラリには、標準タスク用の (おそらく相互に関連する) ルーチンの膨大な武器がありますが、そのフレームワークのプロパティにより、ショートカットが許可されないことがよくあります (常に?)。実際、ほとんどのフレームワークには、基本機能のコア層が実装される、ある種のコア インフラストラクチャがあります。より具体的な機能は基本レイヤーを利用し、コアの周囲の 2 番目のレイヤーに配置されます。

ここでのショートカットとは、コアを使用せずに、第 2 層のルーチンから別の第 2 層のルーチンに直接移動することを意味します。(私のドメインからの) 典型的な例はタイムスタンプです。何らかのタイムスタンプ付きのデータ ソースがあります。ここまでの作業は、ネットワークからデータを読み取ってコアに渡し、他のコードがそれを利用できるようにするだけです。

さて、あなたの業界では、非常に正当な理由でデフォルトのタイムスタンプ形式が変更されました(私の場合、UNIX 時間から GPS 時間に変更されました)。フレームワークが業界固有のものでない限り、業界が時間の核となる表現を変更しようとする可能性は非常に低いため、最終的には次のようなフレームワークを使用することになります。 ほとんど あなたが望むことをします。データにアクセスするたびに、最初にデータを業界標準形式に変換する必要があり、データを変更するたびに、コアが適切と判断する形式に変換し直す必要があります。二重変換せずにソースからシンクにデータを直接渡すことはできません。

これは、手作りのフレームワークが輝く場所です。これはほんの小さな変更であり、現実世界のモデリングに戻りますが、他のすべての (業界固有ではない) フレームワークにはパフォーマンス上の欠点があります。

時間の経過とともに、現実世界とモデルの間の差異が増大します。既製のフレームワークを使用すると、すぐに次のような疑問に直面するでしょう。どうやって表現すればいいのか thisthat またはルーチンをどうやって作るか X 受け入れる/プロデュースする Y.

ここまでは C/C++ に関するものではありませんでした。しかし、何らかの理由でフレームワークを変更できない場合、つまりデータを一方の端からもう一方の端に移動するために二重変換を行う必要がある場合は、通常、追加のオーバーヘッドを最小限に抑えるものを採用します。私の場合、TAI->UTC または UTC->TAI コンバーターは生の C (または FPGA) に任せるのが最善です。問題を些細なものにするようなエレガントな表現や、奥深くスマートなデータ構造は存在しません。これは単なる退屈な switch ステートメントです。それを最適化するのに優れたコンパイラを備えた言語を使用しないのはなぜでしょうか。

他のヒント

パフォーマンスが問題である場合、誰もがC/C ++に手を伸ばすとは思わない。

低レベルのコードを書くことの利点は、CPUサイクルを使用すること、またはメモリが少ない場合があります。しかし、高レベルの言語は、この値の一部を取得するために、低レベルの言語に電話をかけることができることに注意してください。 PythonとJVM言語はこれを行うことができます。

たとえば、デスクトップでScikit-Learnを使用しているデータサイエンティストは、既に最適化されたネイティブルーチンを呼び出して、数の計算を行います。速度の新しいコードを書くことには意味がありません。

分散された「ビッグデータ」コンテキストでは、より一般的にはデータの動きに関するボトルネット(ネットワーク転送とI/O)です。ネイティブコードは役に立ちません。役立つのは、同じコードをより速く実行するのではなく、よりスマートなコードを書くことです。

高レベルの言語では、C/C ++よりも、特定の開発者時間でより洗練された分散アルゴリズムを実装できるようになります。大規模に、データの動きが向上したよりスマートなアルゴリズムは、馬鹿げたネイティブコードを打ち負かします。

また、通常、開発者の時間とバグが新しいハードウェアよりもコストの負荷がかかることも事実です。上級開発者の時間の1年は、2万ドルに完全にロードされる可能性があります。また、数百のサーバーに相当する計算時間を貸し出す1年以上。ほとんどの場合、より多くのハードウェアを投げることを最適化することを気にすることは意味がないかもしれません。

「助成金」と「無効」と「主張」についてのフォローアップがわかりませんか?

私たちが知っているように、デジタルの世界では、同じ仕事をする /期待される結果を得るための多くの方法があります。

コードから来る責任 /リスクは、開発者の肩にあります。

これは小さいですが、.NET Worldの非常に便利な例だと思います。

非常に多くの.NET開発者は、パフォーマンスのためのデータシリアル化 /プロセスのコントロールでビルトインBinaryReader -BinaryWriterを使用しています。

これは、フレームワークのBuilting in BinaryWriterクラスのCSHARPソースコード「オーバーロードされた書き込み方法の1つです。

// Writes a boolean to this stream. A single byte is written to the stream
// with the value 0 representing false or the value 1 representing true.
// 
public virtual void Write(bool value) 
{
     //_buffer is a byte array which declared in ctor / init codes of the class
    _buffer = ((byte) (value? 1:0));

    //OutStream is the stream instance which BinaryWriter Writes the value(s) into it.
    OutStream.WriteByte(_buffer[0]);
}

ご覧のとおり、この方法は、_buffer変数への追加の割り当てなしで記述できます。

public virtual void Write(bool value) 
{
    OutStream.WriteByte((byte) (value ? 1 : 0));
}

割り当てがなければ、数ミリ秒を得ることができます。これは「ほとんど何もない」と受け入れることができますが、数千の執筆(つまり、サーバープロセスに)がある場合はどうでしょうか?

「少数」が2(ミリ秒)であり、数千のインスタンスがわずか2.000であると仮定しましょう。これは、4秒以上のプロセス時間を意味します。

.NETからの対象となり続け、MSDNからBCL -.NETベースクラスライブラリ - のソースコードを確認できる場合、開発者から多くのパフォーマンスが失われることがわかります。

BCLソースからのポイントのいずれかが、開発者がコードでより速く()ループを実装できるwhile()またはforeach()ループを使用することを決定するのが正常です。

この小さな利益は、私たちに合計パフォーマンスを与えてくれます。

そして、binarywriter.write()メソッドに戻る場合。

実際、_bufferの実装に追加の割り当ては、開発者の過失ではありません。これはまさに「安全にとどまる」ことを決定します!

_bufferを使用しないことを決定し、2番目の方法を実装することにしたとします。 Connectionの失われました。なぜなら、チェックや制御メカニズムなしですべてのデータを送信しようとします。接続が失われたら、サーバーとクライアントの両方が送信されたデータが完了したかどうかはわかりません。

開発者が「安全にとどまる」と判断した場合、通常はパフォーマンスコストが実装された「安全な」メカニズムに依存することを意味します。

しかし、開発者が「リスクを獲得する、パフォーマンスを獲得する」と判断した場合、これもせいではありません。「リスクのある」コーディングについての議論があります。

そして、小さなメモとして:商業図書館開発者は、コードがどこで使用するかを知ることができないため、常に安全を維持しようとします。

プログラマーの観点から来ると、フレームワークはパフォーマンスを最優先事項としてターゲットにすることはめったにありません。あなたのライブラリが広く活用されている場合、人々は最も多くを大切にする可能性が高いものは、使いやすさ、柔軟性、信頼性です。

パフォーマンスは一般に、二次競合図書館で評価されます。 「Xライブラリはより速いのでより良いです。」それでも、これらのライブラリは、広くレバレッジできるものに対して最も最適なソリューションをトレードオフすることが非常に頻繁にあります。

フレームワークを使用することにより、本質的に高速なソリューションが存在するというリスクを冒しています。私は、より速いソリューションがほとんど常に存在すると言うまで行くかもしれません。

自分で何かを書くことはパフォーマンスを保証するものではありませんが、自分が何をしているのかを知っていて、かなり限られた要件がある場合、それは役立ちます。

例は、JSONの解析です。 JSONを参照可能なオブジェクトに変えるさまざまな言語には、100のライブラリがあります。その逆も同様です。私は、CPUレジスタですべてを行う1つの実装を知っています。他のすべてのパーサーよりも測定できるほど高速ですが、また非常に限られており、その制限は、あなたが作業しているCPUによって異なります。

高性能環境を構築するタスクに固有のJSONパーサーは、良いアイデアですか?私は100のうち99回の尊敬されるライブラリを活用します。その1つの別々のインスタンスでは、いくつかの追加のCPUサイクルに百万の反復を掛けたものに、開発時間に価値があります。

ライセンス: CC-BY-SA帰属
所属していません datascience.stackexchange
scroll top