web-dev-qa-db-ja.com

ファイルI / Oの設計->処理->ファイルI / Oシステム

私は以前に行った他のものとは非常に異なる新しいデスクトップアプリケーションを設計している最中なので、その基本的なビルディングブロックに関して正しい方向に向けることができれば幸いです。

アプリケーションはバイナリファイルを読み取り、「行ごと」に処理します。データのチャンクが読み取られて処理された後、それをディスクに書き戻します。生データ、つまり元のバイナリファイルは通常、大きすぎてメモリにロードできないため、少しずつ処理する必要があります。 2番目のフェーズ(処理)はあまり計算集約的ではなく、以前の経験から、ディスクへの書き込み部分が最も時間がかかると確信しています。

私が現在考えているのは、3つのスレッド(プロセスではない)です。1つはディスクへのデータのチャンクの読み取りを担当し、もう1つは処理を行い、もう1つはディスクへの書き込みを行います。メインアプリケーション(PythonまたはRust、まだ不明)は、最初のスレッドにメモリバッファーを割り当て、一般的に3つのスレッドのスケジュールを担当します。

これは理にかなっていますか?私の要件は標準の非同期Webアプリの要件と非常に似ていることを承知しているため、これをすべて最初から作成することを避けるのに役立つ重要なツールが不足している可能性があります。

3
HagaiH

複数のスレッドを使用することは、プログラムがCPUにバインドされていて、parallelizeプログラムで複数のCPUコアを使用する場合に最も役立ちます。

これは、シナリオなどのI/Oバウンドの問題には当てはまりません。マルチスレッドでは、システムがまったくスピードアップしない可能性があります。

I/Oバウンド設定では、スレッドの使用は同時/非同期コードを書き込むための1つの方法であるため、複数のスレッドを持つことは依然として有益です。これらのスレッドは、コードを整理しておくための手段にすぎませんが、ほとんどの場合、これらのスレッドはスリープ状態になり、イベントなどを待機します。新しい入力のチャンクが読み込まれたこと。

スレッドを使用する代わりに、多くのプログラムは代わりにイベントループを使用することを好みます。並列処理を除く同時実行性のすべての利点を得ることができますが、複数のスレッドがもたらす頭痛に対処する必要はありません。 PythonとRustはどちらも、特にasyncio(Python)とTokio(Rust)の適切なライブラリを利用できます。

特にI/Oの場合、並列化は役立つよりも有害な場合があります。ここでの多くは、読み書きしている物理ストレージハードウェアに依存します。特にハードディスクドライブは、大きなブロックのシーケンシャルな読み取りを許可すると、はるかに高速になります。同時に別の場所で読み取りまたは書き込みを行うように依頼すると、すべてが遅くなる可能性があります。

純粋なCPU制限の問題でも、スレッドが常に最良の解決策とは限りません。オペレーティングシステムのスレッドは、かなり大きなメモリ構造です。スレッドはオペレーティングシステムによって中断され、スケジュールされます。これには、スレッドA→カーネル→スレッドBのコンテキストスイッチが必要です。これは、ネイティブ関数呼び出しと比較すると低速です。スレッドは、データ構造を共有している場合、互いに同期する必要があります。このようなロックやミューテックスは遅くなる場合と遅くなる場合がありますが、通常、それらを使用する必要は、まったく使用しない場合よりも遅くなります。最後に、ソフトウェアのパフォーマンスは、ソフトウェアがCPUキャッシュをどれだけ効率的に使用できるかに大きく依存します。 2つのスレッドが同じデータ構造(バッファーなど)で動作し、1つのスレッドがこのメモリを変更する場合、他のCPU上のこのメモリのキャッシュを無効にして、後続のアクセスがより遅いRAMに移動するようにする必要があります。

Python=に固有の警告は、CPythonインタープリターがグローバルインタープリターロックを持っていることです。最大で1つのスレッドがPythonコードを同時に解釈できます。独自のスレッドを管理するC拡張機能を使用すると、Pythonでのマルチスレッド化はコードを並列化することはできませんが、並行コードに役立つ場合があります。新しいコードの場合、asyncioは同じことをよりエレガントに行うことができます。

3
amon