我已经编写了以下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堆栈资源管理器,为什么它会消耗这么多性能(高达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;
}
你怎么知道Read
正在阻塞,而不是需要一段时间才能完成它需要做的事情?
IO成本高昂;我完全期望在这个方法中花费的大量时间都在Read
调用内部。你说的70%听起来差不多是对的。你似乎没有滥用这种方法,所以花在阅读上的时间百分比越高,实际上意味着做其他事情的开销就越低。与其说这是在阅读中损失了70%的时间,不如说我认为这是在非阅读活动中损失了30%的时间。这是一个不错的数据,但也有改进的空间。
不过,在深入研究之前,请确保您不在微观优化领域。我现在可以告诉你,这看起来并不是你做错了,所以除非你已经对你的代码进行了基准测试,并确定它的运行速度低于你的需求所能接受的速度,否则不要担心性能。如果你的程序执行得不够快,无法完成任务,那么你需要从目前需要多长时间以及需要多长时间才能"足够快"开始。