0

私はboost :: asioを使ってHttpサーバーを書いています。大きなファイルの場合、ファイル全体をメモリに読み込んでネットワークに送るのを避けるために、私はboost :: asio :: async_writeを使ってネットワーク上で送信する部分を読み込みます。boost :: async_write大きなファイルとメモリ消費

問題は、私のプロデューサ(ファイルから読み込む関数)がコンシューマ(boost :: asio :: async_write)よりもはるかに高速で、大きなファイルのメモリ消費量が大きいことです。

この問題を回避するには、バッファのリストを制限します。シンプルなプロデューサ/コンシューマの問題のように思えますが、その間にスレッドをブロックしたくありません。

私はboost :: io_serviceをn個のスレッドのスレッドプールで構成することができます。大規模なファイルに対するリクエストが多すぎる場合は、もうリクエストを処理していないサーバーで終了したくありません。

私の質問は です - どのようにスレッドをブロックせずにこのメカニズムを設計できますか? - リストのサイズをテストし、大きすぎる場合は、io_service :: postを実行してファイルを読み続けるデッドラインタイマーを生成しますか? - それを処理するより良い方法はありますか?

+0

async_write経由でNバイトを送信しているとします。 async_writeを開始し、同時にファイルから次のNバイトを読み込みます(2つのタスクをポストします)。その後、async_writeが終了したら、同じことを繰り返します。したがって、まだ送信していないファイル部分はメモリに保持しません。 –

答えて

0

読み取りスレッドをブロックすることは、DOS攻撃を防止したい場合はお勧めできません。あなたが避けようとしているのは、同時に大量のリソース(メモリ)を割り当てることです。しかし、オープンファイルストリームの量も制限されています。過負荷状態で読み込みスレッドをブロックし始めると、非常に多くのオープンファイルストリームが非常に高速に取得されます。エラーが発生した場合、プログラムがクラッシュすることはありませんが、他のファイル(ログファイルなど)を開くことができないため、望ましくない動作です。

この問題を回避するには、両方のリソースを気にする必要があります。割り当てられたリソースの量を制限する多くのアルゴリズムがあります。メモリの場合は、読み込みデータのチャンクにリングバッファを使用できます。アトミックカウンタを使用して、割り当てられたリソースの量を追跡し、上限を確立することもできます。セマフォは、この種の問題を解決するためにも使用できます。私は最後の方が好きです。擬似コードはこのようになります。

Semaphore filestreams(maxNumberOfFilestreams); 
Semaphore memory(maxNumberOfAllocatedChunks); 

// Worker thread to read 
void run() { 
    filestream.wait(); 
    while(!eof) { 
     memory.wait(); 
     // Allocate and read 
    } 
    file.close(); 
    filestream.notify() 
} 

// Sending thread() 

void run() { 
    while(true) { 
     // grab chunk, send and free memory 
     memory.notify(); 
    } 
} 

オープンtcp接続も制限されたリソースです。

関連する問題