C# SerialPort.ReadLine()与手动方法相比速度慢吗?

C# SerialPort.ReadLine()与手动方法相比速度慢吗?,c#,serial-port,C#,Serial Port,我最近实现了一个小程序,它读取来自传感器的数据,并将其绘制成图表 数据以5字节的块形式输入,大约每500µs(波特率:500000)。大约3000块组成一条完整的线。因此,总传输时间约为1.5秒 当我在看实时图表时,我注意到显示的内容与当前测量的内容之间存在严重的滞后。调查发现,这一切归结为: SerialPort.ReadLine(); 它比要传输的线路多花费大约0.5秒。因此,每行读取大约需要2秒。有趣的是,没有数据丢失,只是每读一行,数据就会落后更多。这对用户来说非常恼火,所以我不能就这

我最近实现了一个小程序,它读取来自传感器的数据,并将其绘制成图表

数据以5字节的块形式输入,大约每500µs(波特率:500000)。大约3000块组成一条完整的线。因此,总传输时间约为1.5秒

当我在看实时图表时,我注意到显示的内容与当前测量的内容之间存在严重的滞后。调查发现,这一切归结为:

SerialPort.ReadLine();
它比要传输的线路多花费大约0.5秒。因此,每行读取大约需要2秒。有趣的是,没有数据丢失,只是每读一行,数据就会落后更多。这对用户来说非常恼火,所以我不能就这样离开它

我已经实现了我自己的变体,它显示了大约1.5秒的一致时间,并且没有延迟发生。我对自己的实现并不感到自豪(或多或少轮询基流),我想知道是否有办法加速
SerialPort
类的
ReadLine
函数。在我的实现中,我也得到了一些损坏的行,但还没有找到确切的问题

我尝试将
ReadTimeout
更改为1600,但这只产生了
TimeoutException
。尽管数据已经到达

任何关于它为什么慢的解释或修复它的方法都是值得赞赏的

作为旁注:我在一个只有SerialPort.ReadLine()的控制台应用程序上也尝试过这个方法,结果是一样的,所以我排除了我自己的应用程序对
SerialPort
的影响


我不确定这是否相关,但我的实现如下所示:

LineSplitter lineSplitter = new LineSplitter();
async Task<string> SerialReadLineAsync(SerialPort serialPort)
{
    byte[] buffer = new byte[5];
    string ret = string.Empty;

    while (true)
    {
        try
        {
            int bytesRead = await serialPort.BaseStream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false);
            byte[] line = lineSplitter.OnIncomingBinaryBlock(this, buffer, bytesRead);
            if (null != line)
            {
                return Encoding.ASCII.GetString(line).TrimEnd('\r', '\n');
            }
        }
        catch
        {
            return string.Empty;
        }
    }
}

我在2008年与GPS模块交谈时遇到了这个问题。从本质上讲,阻塞函数是脆弱的,解决方案是使用APM

下面是另一个堆栈溢出答案中的血淋淋的细节:


您也可能会感兴趣:

ReadLine不是很好。最好直接使用BaseStream:这很有趣。当您查看参考源代码时,您的代码有什么不同@DaxFohl是的,我读过那篇文章,但它只提到错误和同步是一个问题,并不是说它也很慢。@AndrewDiamond我已经添加了我的代码。也许它可以帮助某人获得答案或其他东西。仅链接的答案在堆栈溢出时没有用处。将相关细节添加到您的答案中,以便OP所需的可操作信息完全包含在您的答案中,或者删除答案。仅链接的答案并不理想,因为有一天链接可能不再解析。但这是指向另一个堆栈溢出答案的链接。死链接问题不可能发生,除非某个沉迷于规则的徽章收集器决定删除有用信息,因为它不符合某些武断的适当性概念。“但这是指向另一个堆栈溢出答案的链接”——如果另一个链接是原问题的答案,那么在这里发布答案是不合适的。原来的问题应该以重复的形式结束,你在这里的帖子只是一个评论,而不是一个答案。坦白地说,我看不出你提供的链接实际上是如何回答这个问题的(所以我不会是那个重复回答原始问题的人),但这是一个完全独立的问题。它提供了一种解决问题的替代方法,而不受性能或可靠性问题的影响,这两个问题都被列为关注点。这不是一个重复的问题,但同样的答案适用,因为使用APM而不是阻塞函数解决了许多问题,这两个问题是。坦率地说,我认为串行阻塞函数应该被弃用,它们的质量很差,而且会鼓励糟糕的实践。
class LineSplitter
{
    // based on: http://www.sparxeng.com/blog/software/reading-lines-serial-port
    public byte Delimiter = (byte)'\n';
    byte[] leftover;


    public byte[] OnIncomingBinaryBlock(object sender, byte[] buffer, int bytesInBuffer)
    {
        leftover = ConcatArray(leftover, buffer, 0, bytesInBuffer);
        int newLineIndex = Array.IndexOf(leftover, Delimiter);
        if (newLineIndex >= 0)
        {
            byte[] result = new byte[newLineIndex+1];
            Array.Copy(leftover, result, result.Length);
            byte[] newLeftover = new byte[leftover.Length - result.Length];
            Array.Copy(leftover, newLineIndex + 1, newLeftover, 0, newLeftover.Length);
            leftover = newLeftover;

            return result;
        }
        return null;
    }

    static byte[] ConcatArray(byte[] head, byte[] tail, int tailOffset, int tailCount)
    {
        byte[] result;
        if (head == null)
        {
            result = new byte[tailCount];
            Array.Copy(tail, tailOffset, result, 0, tailCount);
        }
        else
        {
            result = new byte[head.Length + tailCount];
            head.CopyTo(result, 0);
            Array.Copy(tail, tailOffset, result, head.Length, tailCount);
        }

        return result;
    }
}