1

次の C# 関数を作成しました。

static string ReadLineCRLF(System.IO.Stream Stream, ref byte[] sharedBuffer, int bufferSize = 1024)
{
    StringBuilder responseString = new StringBuilder("");
    string returnString = "";
    byte[] buffer = new byte[bufferSize];
    bool stopreading = false;
    bool firstexecution = true;
    while (!stopreading)
    {
        int readBytes;
        if (firstexecution && sharedBuffer.Length > 0)
        {
            readBytes = sharedBuffer.Length;
            sharedBuffer.CopyTo(buffer, 0);
        }
        else
        {
            readBytes = Stream.Read(buffer, 0, bufferSize); //BLOCKING HERE
        }
        firstexecution = false;
        if (readBytes > 0)
        {
            int crIndex = Array.IndexOf(buffer, (byte)13); //13 = ASCII value for a carriage return
            if (crIndex > -1 && Array.IndexOf(buffer, (byte)10, crIndex + 1) == crIndex + 1) //10 = ASCII value for line feed
            {

                stopreading = true;
                sharedBuffer = readBytes - crIndex - 2  > 0 ? ArraySlice<byte>(buffer, crIndex+2, readBytes-crIndex-2) : new byte[] { };
                readBytes = crIndex;
            }
            if (readBytes > 0)
            {
                responseString.Append(System.Text.Encoding.ASCII.GetString(buffer, 0, readBytes));
            }
            if (stopreading)
            {
                returnString = responseString.ToString();
            }
        }
        if (!stopreading && readBytes <= 0)
        {
            returnString = null;
            stopreading = true;
            sharedBuffer = new byte[] { };
        }
    }
    return returnString;

}

readBytes = Stream.Read(buffer, 0, bufferSize);私のStack Explorerによると、この機能はブロックされており、多くのコンピューターのパフォーマンスを使い果たしています。この関数が行うべき唯一のことは、CRLF ("\r\n") だけで終了するストリームから 1 行を読み取ることです。

MSDN Stream.Readの返品によると、less than the number of bytes requested if that many bytes are not currently available, or zero (0) if the end of the stream has been reached.通常はブロックされ、CPU パフォーマンスを使い果たすことはありません。The implementation will block until at least one byte of data can be read, in the event that no data is available. Read returns 0 only when there is no more data in the stream and no more is expected (such as a closed socket or end of file).

では、私の CLR Stack Explorer によると、なぜこれほど多くのパフォーマンス (最大 70%) を消費するのでしょうか? 論理的な間違いは見当たりません。何バイトか受信できるようになるまで待つべきだと思います。また、この動作は常に発生するわけではなく、Windows サーバーでアプリケーションの実行を開始してから 1 日または 2 日後に発生するようです。

補足説明: バイトはチャンクを使用して読み取られるため、読み取られてバッファに格納されるバイトが多すぎる可能性があります。したがって、共有バッファーを使用して、次の行の読み取りを続行できるようにします。行が完全に読み取られたら、バッファーから削除します。

ArraySlice 関数は次のようになります。

public static T[] ArraySlice<T>(T[] data, int index, int length)
{
    T[] result = new T[length];
    Array.Copy(data, index, result, 0, length);
    return result;
}
4

1 に答える 1

1

それがブロックされていることをどのように知っていますReadか?それが必要なことをするのに時間がかかるだけではありませんか?

IOは高価です。このメソッドで費やされた時間のかなりの部分が呼び出しの内部にあることを完全に期待しReadます。あなたが言う70%は正しいと思います。メソッドを誤用しているようには見えないので、読み取りに費やされる時間の割合が高いほど、他のすべてを実行するオーバーヘッドが少なくなることを意味します。読書をする時間の70%を失うと考えるのではなく、読書以外の活動をする時間の30%を失うと私は考えています。悪い統計ではありませんが、改善の余地がないわけでもありません。

ただし、深く掘り下げる前に、マイクロ最適化の領域にいないことを確認してください。これで、すべてが間違っているようには見えないので、コードのベンチマークを行い、要件に対して許容できる速度よりも実行速度が遅いと判断しない限り、パフォーマンスについて心配する必要はありません。 。プログラムがその仕事をするのに十分な速さで実行されていない場合は、現在の所要時間と「十分な速さ」になるのに必要な時間から始める必要があります。

于 2012-08-30T19:04:28.623 に答える