Приложение для многопоточной торговли акциями в режиме реального времени - PullRequest
13 голосов
/ 16 сентября 2010

Я создаю многопоточное приложение реального времени в WPF, но у меня возникают трудности с обновлением пользовательского интерфейса.

У меня есть фоновый рабочий поток, содержащий логику, которая определяет, какие сделки отправлять врынок.Когда действительная сделка отправляется на рынок, я получаю обновления статуса по этим сделкам через события в моем главном окне приложения.У меня есть другие события, где я получаю обновления цен в режиме реального времени.

Через эти события я обновляю пользовательский интерфейс.Теперь кажется, что я получаю события так быстро через приложение, что пользовательский интерфейс не может идти в ногу со скоростью, с которой принимаются события - заставляя пользовательский интерфейс обновляться медленно или вообще не обновляться.По сути, пользовательский интерфейс зависает.После того, как все события сработали, пользовательский интерфейс снова медленно реагирует.Как только он полностью реагирует, пользовательский интерфейс отображает данные, которые я ожидаю.

Мой вопрос: как я могу обновить пользовательский интерфейс в режиме реального времени так быстро, как я получаю события?Я уже давно борюсь с этим, поэтому любая помощь будет признательна.

Заранее спасибо!

Ответы [ 2 ]

11 голосов
/ 16 сентября 2010

Вместо того, чтобы рабочий поток отправлял обновления в поток пользовательского интерфейса с помощью событий, рассмотрите возможность периодического извлечения (или опроса) потоком пользовательского интерфейса. Метод push хорош во многих ситуациях, но имеет два основных недостатка, которые работают против вас.

  • Где-то существует дорогостоящая операция маршалинга, которая передает выполнение метода для безопасного выполнения обновлений пользовательского интерфейса (по крайней мере, должно быть).
  • Рабочий поток получает возможность диктовать, как часто пользовательский интерфейс должен обновляться и, как следствие, сколько работы он должен выполнять. Это может легко сокрушить насос сообщений.

Я предлагаю использовать общую очередь, в которой рабочий поток ставит в очередь структуру данных, содержащую обновление, а поток пользовательского интерфейса удаляет и обрабатывает ее. Вы можете сделать так, чтобы поток пользовательского интерфейса опрашивал очередь через стратегически выбранный интервал, чтобы он никогда не зависал. Очередь будет выступать в качестве буфера, а не насоса сообщений интерфейса пользователя. Он будет уменьшаться и увеличиваться по мере увеличения и уменьшения количества обновлений. Вот простая диаграмма того, о чем я говорю.

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

Сначала я бы начал с простого подхода к очереди, но вы могли бы перейти к следующему логическому этапу создания конвейера, в котором в потоке обновлений участвуют 3 потока. Рабочий поток ставит в очередь обновления, а поток пользовательского интерфейса удаляет их, как и раньше. Но новый поток может быть добавлен к миксу, который управляет количеством обновлений, ожидающих в очереди, и поддерживает его в управляемом размере. Это будет сделано путем пересылки всех обновлений, если очередь остается небольшой, но переключится в безопасный режим и начнет отбрасывать обновления, без которых вы можете жить, или объединять многие в одно, если можно определить разумную операцию объединения. Вот простая диаграмма того, как этот шаблон может работать.

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

Опять же, начните с простого подхода с одной очередью. Если вам нужно больше контроля, перейдите к шаблону конвейера. Я успешно использовал оба.

7 голосов
/ 16 сентября 2010

Возможно, вам нужно объединить полученные события так, чтобы не каждый тик приводил к обновлению графического интерфейса.Пакетируйте их, если ваш графический интерфейс уже обновляется, и выполняйте обработку следующего пакета только тогда, когда он будет готов.Если фид большого объема (часто в случае активных обновлений торговых данных), вы не сможете создать графический интерфейс, который отображает каждый отдельный тик в качестве отдельного триггера обновления.

...