任意のサイズのバイト チャンクを先頭に効率的に追加し、末尾から任意のサイズのバイト チャンクを効率的にポップできる FIFO バッファを実装するにはどうすればよいですか?
バックグラウンド:
ファイルのようなオブジェクトから任意のサイズのチャンクでバイトを読み取るクラスがあり、それ自体がクライアントが任意のサイズのチャンクでバイトを読み取ることができるファイルのようなオブジェクトです。
私がこれを実装した方法は、クライアントがバイトのチャンクを読みたいときはいつでも、クラスが基礎となるファイルのようなオブジェクトから (それらのオブジェクトに適切なチャンク サイズで) 繰り返し読み取り、そのバイトを FIFO の先頭に追加することです。要求されたサイズのチャンクをクライアントに提供するのに十分なバイトがキューにあるまでキューに入れます。次に、それらのバイトをキューの末尾からポップして、クライアントに返します。
基になるファイルのようなオブジェクトのチャンク サイズが、クライアントがクラスから読み取るときに使用するチャンク サイズよりもはるかに大きい場合に発生するパフォーマンスの問題があります。
基盤となるファイルのようなオブジェクトのチャンク サイズが 1 MiB で、クライアントが読み取るチャンク サイズが 1 KiB であるとします。クライアントが初めて 1 KiB を要求したとき、クラスは 1 MiB を読み取って FIFO キューに追加する必要があります。次に、そのリクエストと後続の 1023 リクエストに対して、クラスは FIFO キューの末尾から 1 KiB をポップする必要があります。これは、サイズが 1 MiB から 0 バイトに徐々に減少し、その時点でサイクルが再び開始されます。
現在、これを StringIO オブジェクトで実装しています。StringIO オブジェクトの最後に新しいバイトを書き込むのは高速ですが、最初からバイトを削除するのは非常に遅くなります。これは、前のバッファー全体から最初のバイトのチャンクを差し引いたコピーを保持する新しい StringIO オブジェクトを作成する必要があるためです。
同様の問題を扱う SO の質問は、deque コンテナーを指す傾向があります。ただし、deque は双方向リンク リストとして実装されます。チャンクを両端キューに書き込むには、チャンクをオブジェクトに分割する必要があり、それぞれに 1 バイトが含まれます。次に、deque は、格納するために各オブジェクトに 2 つのポインターを追加します。おそらく、バイト数と比較して、メモリ要件が少なくとも 1 桁増加します。また、リンクされたリストをトラバースし、各オブジェクトを処理して、チャンクをオブジェクトに分割し、オブジェクトをチャンクに結合するには、長い時間がかかります。