残念ながら、TCPはメッセージを転送できず、バイトストリームのみを転送できます。メッセージを転送したい場合は、上にプロトコルを適用する必要があります。高性能に最適なプロトコルは、メッセージの長さを指定する健全性チェック可能なヘッダーを使用するプロトコルです。これにより、データをバイト単位で反復して終了を探すことなく、適切なバッファオブジェクトに正しい量のデータを直接読み取ることができます。 of-メッセージ文字。次に、バッファPOINTERを別のスレッドにキューオフし、次のメッセージのために新しいバッファオブジェクトを作成/デプールできます。これにより、バルクデータのコピーが回避され、大きなメッセージの場合、メッセージオブジェクトポインタに非ブロッキングキューを使用しても意味がないほど効率的です。
利用可能な次の最適化は、オブジェクト* buffersをプールして、継続的な新規/破棄を回避し、ネットワーク受信スレッドで再利用するために*buffersをコンシューマースレッドでリサイクルすることです。これは、ConcurrentQueueを使用して行うのはかなり簡単です。できれば、プールが一時的に空になった場合に、データの破損やsegfaults/AVの代わりにフロー制御を許可するようにブロックします。
次に、各*bufferデータメンバーの先頭に[cachelinesize]'dead-zone'を追加して、スレッドが他のスレッドとデータを誤って共有しないようにします。
その結果、レイテンシー、CPUの浪費、またはキャッシュスラッシングがほとんどない、コンシューマースレッドへの完全なメッセージのハイバンドフローが実現します。24コアすべてが、さまざまなデータでフラットアウトで実行できます。
マルチスレッドアプリでバルクデータをコピーすることは、貧弱な設計と敗北を認めています。
ファローアップ..
プロトコルが異なるため、データの反復に固執しているようです:(
偽共有のないPDUバッファオブジェクト、例:
typedef struct{
char deadZone[256]; // anti-false-sharing
int dataLen;
char data[8388608]; // 8 meg of data
} SbufferData;
class TdataBuffer: public{
private:
TbufferPool *myPool; // reference to pool used, in case more than one
EpduState PDUstate; // enum state variable used to decode protocol
protected:
SbufferData netData;
public:
virtual reInit(); // zeros dataLen, resets PDUstate etc. - call when depooling a buffer
virtual int loadPDU(char *fromHere,int len); // loads protocol unit
release(); // pushes 'this' back onto 'myPool'
};
loadPDUには、生のネットワークデータへのポインタが渡されます。0を返します-PDUをまだ完全にアセンブルしていないことを意味するか、またはPDUを完全にアセンブルするために生のネットワークデータから取得したバイト数です。この場合、それをキューに入れ、別のPDUをデプールして、loadPDU()を呼び出します。未使用の生データの残りを使用して、次の生データを入力します。
必要に応じて、さまざまな派生バッファクラスのさまざまなプールを使用して、さまざまなプロトコル(TbufferPool [Eprotocols]の配列)を提供できます。TbufferPoolは単なるBlockingCollectionキューである可能性があります。管理はほとんど簡単になります-キューのチェーンの最後で何かがrelease()を呼び出す限り、バッファはシステム全体のキューで送信され、統計を表示するGUIに送信され、次にロガーに送信される可能性があります。
明らかに、「実際の」PDUオブジェクトには、より多くのメソッド、データユニオン/構造体、イテレータ、およびプロトコルを操作するための状態エンジンがロードされますが、それはとにかく基本的な考え方です。主なことは、管理とカプセル化が簡単であり、2つのスレッドが同じバッファーインスタンスで動作することはないため、データの解析/アクセスにロック/シンクロは必要ありません。
そうです。1つのポインタをプッシュ/ポップするために必要な時間より長くロックされたままにする必要がないため、実際の競合の可能性は非常に低くなります。従来のブロッキングキューでさえ、カーネルロックを使用する必要はほとんどありません。