NetworkStream上的ReadAsync似乎正在使用我的所有CPU

时间:2018-01-11 01:12:33

标签: c# asynchronous profiling networkstream

我有以下方法,它以异步方式从NetworkStream读取和反序列化数据包。一切正常,但CPU分析显示我等待异步读取的最后一行是我的大部分CPU使用来自的地方。

我是否严重/低效地实现了这个,或者NetworkStream的异步实现是否存在某种固有的错误?

public async Task<Packet> ReadAsync(CancellationToken cancellationToken)
{
    while (true)
    {
        // Read through the available bytes until we find the start of a packet
        while (start < length && buffer[start] != Packet.STX)
            start++;

        // Align the packet (and all successive bytes) with the beginning of the buffer
        if (start > 0)
        {
            if (start < length)
                Array.Copy(buffer, start, buffer, 0, length - start);

            length -= start;
            start = 0;
        }

        // Read through the available bytes until we find the end of the packet
        while (end < length && buffer[end] != Packet.ETX)
            end++;

        // If we have a whole packet in the buffer, deserialize and return it
        if (end < length)
        {
            byte[] data = new byte[end + 1];
            Array.Copy(buffer, data, end + 1);
            byte[] decoded = null;
            Packet packet = null;

            try
            {
                decoded = Packet.Decode(data);
            }
            catch (Exception ex)
            {
                throw new IOException("Could not decode packet", ex);
            }

            if (decoded != null)
            {
                try
                {
                    packet = Packet.Deserialize(decoded);
                }
                catch (Exception ex)
                {
                    throw new IOException("Could not deserialize packet", ex);
                }
            }

            Array.Copy(buffer, end + 1, buffer, 0, length - (end + 1));
            length -= end + 1;
            end = 0;

            if (packet != null)
                return packet;
        }

        // If we read all available bytes while looking for the end of a packet
        if (end == length)
        {
            if (length == buffer.Length)
                throw new InsufficientMemoryException();

            length += await Stream.ReadAsync(buffer, length, buffer.Length - length, cancellationToken);
        }
    }
}

CPU profiling results

1 个答案:

答案 0 :(得分:0)

我已经更新了代码,以便在每次调用ReadAsync之间保持睡眠状态,大致相当于上次读取所花费的时间:

var stopwatch = new Stopwatch();
var iteration = 0;

while (true)
{
    // ...
    var delay = stopwatch.Elapsed;
    stopwatch.Restart();

    if (iteration % 10 != 0)
        await Task.Delay(delay);

    length += await Stream.ReadAsync(buffer, length, buffer.Length - length, cancellationToken);
    stopwatch.Stop();
    iteration += 1;
}

这大大降低了CPU的使用率。这绝对是一种解决方法,因为它没有解决这个问题,但它确实有效。我很想听听别人对这个问题的回答或意见。