2011-05-13 17 views
7

Actualmente estoy escribiendo una aplicación que se comunica con un servo integrado a través de una conexión en serie.Método más rápido de subprocesamiento múltiple del puerto serie Análisis de datos C#

El motor envía datos de posición a una velocidad de hasta 1000 veces/segundo. Lo que estoy tratando de lograr es poder formatear los datos que regresan (despojándolos de espacios en blanco, nuevas líneas, etc.) y analizarlos para extraer los datos relevantes de las cadenas recibidas.

Actualmente, tengo el manejador de eventos de datos recibidos, leen los datos, los formatean usando una serie de llamadas al método string.replace, y lo añaden a una cadena que actúa como un buffer. Luego, usando hilos, reviso constantemente el buffer mientras se llena para un delimitador particular (en mi caso "\ r") que significa el final de un mensaje del motor, luego quito ese mensaje del buffer y lo imprimo a un rico campo de texto.

Hay dos problemas con este enfoque. Una es que debido a que el motor transmite datos de posición a una velocidad tan alta, la memoria intermedia se llena más rápido de lo que los hilos pueden procesar los datos. Por lo tanto, cuando envío un comando al motor, actúa de inmediato, pero la respuesta se demora unos segundos porque todos los datos anteriores en el buffer deben procesarse primero. En segundo lugar, tener dos hilos que ejecutan un método que implementa una estructura while (verdadera) significa que la utilización del procesador se dispara y en pocos segundos los ventiladores en la PC están en máx.

¿Existe una forma mejor de manejar los datos?

Aquí está mi código de controlador de eventos:

//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; 
      } 

    } 

Aquí es el método que los hilos se ejecutan:

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)); 
       } 
      } 
     } 
    } 
+2

He encontrado el problema. No es que el programa no pueda procesar los datos en el búfer lo suficientemente rápido, es que el programa no puede escribir en el cuadro de texto enriquecido lo suficientemente rápido. El código que estaba usando solo hizo algo como 'textBox1.text + = myText; '. Al imprimir en la consola, no tengo problemas con el almacenamiento intermedio que crece más rápido de lo que el programa procesa los datos como dije anteriormente. – isometrik

Respuesta

0

En general me gustaría utilizar una colección de bloqueo entre un hilo de lectura que se lee únicamente a partir de el zócalo y un hilo de análisis.
En términos de rendimiento, consulte el uso de división para el análisis: esto es mucho más rápido que reemplazar dentro de una cadena. Usted debe buscar en el uso de una la clase StringBuilder expresión regular y/o - se debe utilizar 1 de expresión alternativas
El código expresiones regulares se vería así:

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

Pero si mi objetivo es eliminar un personaje, necesitaría usar un comando dividido y un comando de concatenación. Esto todavía sería más rápido? – isometrik

+0

¿Por qué quitas caracteres primero? Es una operación realmente costosa; solo lo haces si tienes problemas de memoria real. – weismat

2

Hay un par de cosas que puede hacer para mejorar esto dramáticamente.

1) Cree un analizador de estado-máquina que analiza los datos de entrada carácter por carácter. Cuando haya creado un "mensaje" completo, agréguelo a una estructura List<MyMessage>.

2) Use un ListView virtualizado o DataGridView para mostrar el List<MyMessage>.

3

Su parseBuffer se pondrá en marcha sin control incluso si no hay datos nuevos desde la última vez que lo intentó.

Puede mitigar esto con la señalización.

private AutoResetEvent waitHandle = new AutoResetEvent(false); 

Gatillo la señal en dataReceived

//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 
     } 

} 

espera de la señal en parseBuffer

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)); 
      } 
     } 
    } 
} 
+0

Esto funcionaría si no fuera por el hecho de que se pueden colocar varios mensajes en el búfer a la vez, por lo que estableciendo waitHandle solo se procesa un mensaje. He cambiado "if (readBuffer.IndexOf (" \ r ")> 0)" while (readBuffer.IndexOf ("\ r")> 0) ". – isometrik

+0

bloqueo (esto) debe evitarse por guidilines –

+0

Es un Al igual que en las Transmisiones TCP, debe asegurarse de verificar lo que recibe por un potencial mayor al esperado, ya que a veces se pueden recibir múltiples envíos en una operación de recepción. –

0

En los datos recibidos evento leer los datos entrantes como bytes sin formato y se guardan en una cola. No procese los datos en el controlador de eventos. Luego use algo similar a lo que dijo albin para procesar los datos en otro método. Lo importante es permitir que el manejador de eventos dispare tan a menudo como sea posible y no haga más de lo requerido.

Cuestiones relacionadas