Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/318.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 串口数据解析的最快多线程方法#_C#_Parsing_Serial Port - Fatal编程技术网

C# 串口数据解析的最快多线程方法#

C# 串口数据解析的最快多线程方法#,c#,parsing,serial-port,C#,Parsing,Serial Port,我目前正在编写一个应用程序,通过串行连接与集成伺服进行通信 电机以高达1000次/秒的速率发送位置数据。我试图实现的是能够格式化返回的数据(通过去除空白、新行等),并对其进行解析以从接收到的字符串中提取相关数据 目前,我让data received事件处理程序读取数据,使用一系列string.replace方法调用对其进行格式化,并将其附加到充当缓冲区的字符串中。然后,使用线程,在缓冲区填充特定分隔符(在我的示例中为“\r”),表示来自马达的一条消息的结束时,我不断检查缓冲区,然后从缓冲区中删除

我目前正在编写一个应用程序,通过串行连接与集成伺服进行通信

电机以高达1000次/秒的速率发送位置数据。我试图实现的是能够格式化返回的数据(通过去除空白、新行等),并对其进行解析以从接收到的字符串中提取相关数据

目前,我让data received事件处理程序读取数据,使用一系列string.replace方法调用对其进行格式化,并将其附加到充当缓冲区的字符串中。然后,使用线程,在缓冲区填充特定分隔符(在我的示例中为“\r”),表示来自马达的一条消息的结束时,我不断检查缓冲区,然后从缓冲区中删除该消息并将其打印到富文本字段

这种方法有两个问题。一个原因是,由于马达以如此高的速率传输位置数据,因此缓冲区的填充速度比线程处理数据的速度快。因此,当我向马达发送命令时,它会立即动作,但响应会延迟几秒钟,因为必须首先处理缓冲区中所有前面的数据。其次,让两个线程运行一个实现while(true)结构的方法意味着处理器利用率猛增,几秒钟内pc中的风扇达到最大

是否有更好的方法处理数据

以下是我的事件处理程序代码:

 //data recieved event handler
    private void dataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
    {
        string tmp;

            tmp = sp.ReadExisting();

            //cut out any unnecessary characters
            tmp = tmp.Replace("\n", "");
            tmp = tmp.Replace(",", "\r");
            tmp = tmp.Replace(" ", "");

            lock (this)
            {
                //put all received data into the read buffer
                readBuffer += tmp;
           }

    }
以下是线程执行的方法:

 private void parseBuffer()
    {
        while (true)
        {
            //obtain lock, parse one message from buffer
            lock (this)
            {
                if (readBuffer.IndexOf("\r") > 0)
                {
                    String t = readBuffer.Substring(0, readBuffer.IndexOf("\r") + 1);
                    readBuffer = readBuffer.Replace(t, "");
                    dataReady(this, new CustomEventArgs(t, null));
                }
            }
        }
    }

一般来说,我会在只从套接字读取的读取器线程和解析线程之间使用阻塞集合。
在性能方面,请看使用拆分进行解析——这比在字符串中替换要快得多。您应该考虑使用正则表达式和/或StringBuilder类-您应该使用1个表达式和可选项
正则表达式代码如下所示:

string pattern = " |\\n|\\r";
string replacement = " "; 
regex rgx = new Regex(pattern);
string result = rgx.Replace(input, replacement);

你可以做一些事情来显著改善这一点

1) 构建一个状态机解析器,该解析器一次解析一个字符的输入数据。当它构建了一个完整的“消息”后,将其添加到
列表
结构中


2) 使用虚拟化的ListView或DataGridView显示
列表

即使自上次尝试后没有新数据,您的
解析缓冲区
也会疯狂旋转

您可以通过发送信号来缓解这种情况

private AutoResetEvent waitHandle = new AutoResetEvent(false);
在接收到的数据中触发信号

//data recieved event handler
private void dataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
    string tmp;

        tmp = sp.ReadExisting();

        //cut out any unnecessary characters
        tmp = tmp.Replace("\n", "");
        tmp = tmp.Replace(",", "\r");
        tmp = tmp.Replace(" ", "");

        lock (this)
        {
            //put all received data into the read buffer
            readBuffer += tmp;
            waitHandle.Set(); // <-- tell parseBuffer that new data is available
       }

}

在DataReceived事件中,将传入数据作为原始字节读取并存储在队列中。不要处理事件处理程序中的数据。然后使用类似于阿尔宾所说的方法,用另一种方法处理数据。重要的是允许eventhandler尽可能频繁地触发,并且不再执行所需的操作。

但如果我的目标是删除字符,则需要同时使用split命令和concatenation命令。这会更快?为什么要先删除字符?这是一个非常昂贵的操作,只有在内存出现问题时才执行。如果不是因为几个消息可能一次放在缓冲区上,那么这会起作用,因此通过设置waitHandle,只处理一条消息。我将“if(readBuffer.IndexOf(“\r”)>0)”更改为while(readBuffer.IndexOf(“\r”)>0)”每个guidilines都应该避免。这有点像TCP流,你需要确保检查你接收到的信息是否可能超过你的预期,因为有时一次接收操作可以接收多个发送。我发现了问题。不是程序不能足够快地处理缓冲区中的数据,而是程序cant以足够快的速度写入富文本框。我使用的代码只是执行了类似于
textBox1.text+=myText;
的操作。当打印到控制台时,我没有遇到缓冲区增长速度快于程序处理上述数据速度的问题。
private void parseBuffer()
{
    while (true)
    {
        waitHandle.WaitOne(); // <-- waits until there is more data to parse
        //obtain lock, parse one message from buffer
        lock (this)
        {
            if (readBuffer.IndexOf("\r") > 0)
            {
                String t = readBuffer.Substring(0, readBuffer.IndexOf("\r") + 1);
                readBuffer = readBuffer.Replace(t, "");
                dataReady(this, new CustomEventArgs(t, null));
            }
        }
    }
}