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);根据我的堆栈资源管理器,此功能被阻塞并消耗了大量计算机性能。这个函数唯一应该做的就是从一个只以 CRLF ("\r\n") 结束的流中读取一行。

根据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 服务器上开始执行应用程序后一两天发生。

附加说明:由于使用块读取字节,可能是读取了太多字节并将其存储在缓冲区中。因此我使用了一个共享缓冲区,允许它再次使用它来继续阅读下一行。完全读取一行后,我将其从缓冲区中删除。

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 回答