2010-09-16 17 views
13

Estoy construyendo una aplicación multiproceso en tiempo real en WPF, pero estoy teniendo dificultades para actualizar la interfaz de usuario.WPF Real Time Multithreaded Stock Trading Application

Tengo un hilo de trabajador de fondo que contiene la lógica que determina qué comercios enviar al mercado. Cuando se envía una operación válida al mercado, recibo actualizaciones de estado en estas transacciones mediante eventos en la ventana principal de mi aplicación. Tengo otros eventos en los que recibo actualizaciones de precios en tiempo real.

A través de estos eventos, apago la IU. Ahora parece que recibo eventos tan rápidamente a través de la aplicación, que la IU no puede mantenerse al día con la velocidad a la que se reciben los eventos, lo que hace que la IU se actualice lentamente o no se actualice. Esencialmente, la IU se congela. Después de que todos los eventos se hayan disparado, la IU lentamente vuelve a ser receptiva. Una vez que responde completamente, la IU muestra los datos que estoy esperando.

Mi pregunta es, ¿cómo puedo obtener la interfaz de usuario para actualizar en tiempo real tan rápido como recibo eventos? He estado luchando con esto desde hace un tiempo, por lo que cualquier ayuda sería apreciada.

¡Gracias de antemano!

Respuesta

11

En lugar de tener el subproceso de trabajo empujar las actualizaciones al subproceso de interfaz de usuario a través de eventos, considere tener el subproceso de interfaz de usuario extraer (o encuesta) periódicamente. El método push está bien en muchas situaciones, pero tiene dos desventajas principales que lo perjudican.

  • hay una operación de cálculo de referencias caro en alguna parte que está transfiriendo ejecución de un método para realizar las actualizaciones de interfaz de usuario de manera segura (por lo menos hay debería BE).
  • El subproceso de trabajador llega a dictar con qué frecuencia debe actualizar la UI y, por implicación, cuánto trabajo debe realizar. Puede abrumar fácilmente a la bomba de mensajes.

Propongo el uso de una cola compartida en la que el hilo del trabajador enqueará una estructura de datos que contiene la actualización y el hilo de la interfaz de usuario la quitará de la cola y la procesará. Puede hacer que la interfaz de usuario muestre la cola en un intervalo elegido estratégicamente para que nunca se atasque. La cola actuará como el búfer en lugar de la bomba de mensajes de UI. Se reducirá y crecerá a medida que la cantidad de actualizaciones disminuya y fluya. Aquí hay un diagrama simple de lo que estoy hablando.

[Worker-Thread] -> [Queue] -> [UI-Thread] 

Me gustaría empezar con la propuesta de cola sencilla principio, pero que podría llevar esto al siguiente paso lógico de la creación de una tubería en la que hay 3 hilos que participan en el flujo de cambios. El subproceso de trabajo pone en cola las actualizaciones y el subproceso de la interfaz de usuario las deque como antes. Sin embargo, se podría agregar un nuevo subproceso a la mezcla que gestiona el número de actualizaciones que esperan en la cola y lo mantiene en un tamaño manejable. Lo hará reenviando todas las actualizaciones si la cola sigue siendo pequeña, pero cambiará a modo seguro y comenzará a descartar las actualizaciones que pueda usar sin combinar muchas en una si se puede definir una operación de fusión razonable. Aquí hay un diagrama simple de cómo este patrón podría funcionar.

[Worker-Thread] -> [Queue-1] -> [Pipeline-Thread] -> [Queue-2] -> [UI-Thread] 

Nuevamente, comience con el enfoque simple de una cola.Si necesita más control, vaya al patrón de tuberías. He usado los dos satisfactoriamente.

+0

Fantástico , gracias Brian. Esa es la respuesta que estaba buscando. En pocas palabras, en lugar de permitir que los eventos planteados actualicen la IU, ponerlos en cola, tener un temporizador que muestre periódicamente estas actualizaciones fuera de la cola y actualice la IU. De esa forma, la UI se actualiza dentro de su control, y el intervalo del temporizador puede ajustarse de acuerdo con mis necesidades. – c0D3l0g1c

+0

¡Exactamente! Deje que la IU dicte cuándo está listo para actualizar en lugar de pasar la responsabilidad al hilo del trabajador. –

7

Es probable que necesite unir los eventos recibidos de forma tal que no todos los tics tengan como resultado una actualización de la GUI. Agruparlos si su GUI ya se está actualizando, y hacer que la GUI procese el siguiente lote solo cuando esté listo. Si el canal de información es de alto volumen (frecuentemente es el caso con actualizaciones de datos de comercio activo), no podrá crear una GUI que refleje cada tilde individual como su propio activador de actualización autónomo.

+0

+1 generalmente solo se puede hacer una cantidad limitada de llamadas separadas al subproceso de la interfaz de usuario por unidad de tiempo antes de que deje de responder. Hacer actualizaciones masivas de elementos como listas de interfaz de usuario en un intervalo establecido también podría ayudar inmensamente ^^ –