我编写了以下 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;
}