2

TCP リンク経由でデータを送信するプログラムがあります。ディスクとネットワークの両方に対して非同期読み取りと書き込みを使用しています。中間にDeflateStreamを配置すると(つまり、ネットワーク リンクに書き込む前に圧縮し、データを受信して​​ディスクに書き出すときに解凍します)、圧縮側で CPU バウンドになります。これにより、最大転送速度が約300 KB/s. ただし、圧縮ステップを削除すると、I/O がディスクにバインドされ、転送速度が40,000 KB/s.

厳密な LAN 条件の下では、I/O の上限は常に 300 KB/秒を超えますが、プログラムがインターネット経由で実行されている場合、ネットワーク IO の制限は 300 KB/秒未満になる可能性があります。

I/O バウンドでネットワーク/ディスク リンクが制限要因なのか、それとも CPU バウンドで圧縮の動作が最も速度を低下させているのかを検出したいと考えています。実行時にプログラムが CPU または I/O によって制限されているかどうかを検出して、プロトコルを切り替えて可能な限り最高の転送速度を得るにはどうすればよいですか?

private static void SendFile(string filename, NetworkStream stream, int sendBufferSize)
{
    using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, 4096, FileOptions.Asynchronous | FileOptions.SequentialScan))
    using (var ds = new DeflateStream(stream, CompressionMode.Compress))
    {
        StreamUtilities.CopyAsync(fs, ds, sendBufferSize);
    }
}

public static void CopyAsync(Stream sourceStream, Stream destStream, int bufferSize = 4096)
{
    Byte[] bufferA = new Byte[bufferSize];
    Byte[] bufferB = new Byte[bufferSize];

    IAsyncResult writeResult = null;
    IAsyncResult readResult = null;

    bool readBufferA = false;
    int read;

    readResult = sourceStream.BeginRead(bufferA, 0, bufferA.Length, null, null);
    //Complete last read
    while ((read = sourceStream.EndRead(readResult)) > 0)
    {
        if (readBufferA)
        {
            PerformOperations(sourceStream, destStream, bufferA, bufferB, ref readResult, ref writeResult, read);
        }
        else
        {
            PerformOperations(sourceStream, destStream, bufferB, bufferA, ref readResult, ref writeResult, read);
        }

        //Flip the bit on the next buffer
        readBufferA = !readBufferA;
    }
    if (writeResult != null)
        destStream.EndWrite(writeResult);
}

private static void PerformOperations(Stream sourceStream, Stream destStream, Byte[] readBuffer, Byte[] writeBuffer, ref IAsyncResult readResult, ref IAsyncResult writeResult, int bytesToWrite)
{
    //Start next read
    readResult = sourceStream.BeginRead(readBuffer, 0, readBuffer.Length, null, null);

    //End previous write
    if (writeResult != null)
        destStream.EndWrite(writeResult);
    writeResult = destStream.BeginWrite(writeBuffer, 0, bytesToWrite, null, null);
}
4

1 に答える 1

7

1 つのオプションは、2 つの側面をプロデューサー/コンシューマー キューに分離することです。コンプレッサーはブロックをキューに書き込み、IO を実行するだけのスレッドによって消費されます。

その方法:

  • 非同期 IO に移行することなく、IO の発生中に圧縮できます。
  • CPU バウンド (通常はキューが空であるか、一時的に 1 つのブロックが存在する) か、IO バウンド (キューが送信されるよりも速く圧縮するにつれてキューが徐々に大きくなる) かどうかを検出できます。
  • ちょっとした作業で、圧縮をマルチスレッド化できます。ブロックの順序を追跡する必要がありますが、それは実現可能です。
于 2012-11-26T21:25:29.500 に答える