Как кэшировать данные в реальном времени? - PullRequest
2 голосов
/ 10 мая 2011
  • Я работаю над приложением Windows Forms (.NET 4.0).
  • Моя форма содержит диаграмму «Быстрая линия» с использованием элемента управления диаграммы Microsoft, включенного в VS2010.
  • Диаграмма заполняется примерно 20 000 точками данных.
  • Затем мое приложение начинает получать рыночные данные с сервера через DDE (динамический обмен данными) в режиме реального времени и добавляет их в диаграмму.

Примечание: У меня нет контроля над сервером, поэтому мне приходится иметь дело только с DDE, даже если это устаревшая технология.VS больше не поддерживает DDE, поэтому я использую библиотеку Ndde , которая работает как шарм.

Сначала мы подключаемся к серверу, создаем цикл advise, а затем подписываемся на OnAdviseСобытие для получения уведомлений о новых данных:

Dim client As DdeClient = New DdeClient("ServerApplication", "Bid")

Private Sub StartDDE()
    client.Connect()
    client.StartAdvise("EURUSD", 1, True, 60000)
    AddHandler client.Advise, AddressOf OnAdvise
End Sub

Теперь мы можем поместить команды для обновления графика внутри события:

Private Sub OnAdvise(ByVal sender As Object, ByVal args As DdeAdviseEventArgs)
    Dim myPrice As Double = args.Text
    Chart1.Series("Bid").Points.AddY(myPrice)
End Sub

Вы получите идею.

ПРОБЛЕМА:

Это отлично работает в течение нескольких секунд, пока не произойдет сбой диаграммы, выдав исключение: «Сбор был изменен; операция перечисления может не выполняться».

Iя потратил много времени на изучение причин, которые могут быть причиной этого в моем конкретном случае, и я пришел к выводу, что причина в том, что диаграмма получает данные быстрее, чем она может обработать.Он уже загружен большим количеством данных и требует определенного времени (менее секунды) для добавления полученных данных в новую DataPoint и аннулирования (обновления) самого себя.В то время как сервер часто отправляет значения данных очень быстро (например, 5 мс между).Итак, я попробовал следующее:

System.Threading.Thread.Sleep(800)
Chart1.Series("Bid").Points.AddY(myPrice)

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

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

Мой вопрос: как бы вы это сделали?

Приветствуются другие предложения!

Ответы [ 2 ]

2 голосов
/ 10 мая 2011

Скорее всего, это проблема, вызванная попыткой изменить элемент пользовательского интерфейса из потока, отличного от потока пользовательского интерфейса.

То, как вы сейчас его кодировали, обработчик события DdeClient.Advise выполняется в рабочем потоке, управляемом библиотекой. Видите, DDE отстой, и, поскольку он отстой, у него есть следующие требования: он должен работать в потоке с обработчиком сообщений. 1 Чтобы библиотека была совместима с другими типами приложений, кроме оконных форм, я закодировал ее таким образом. таким образом, он создаст выделенный поток с циклом сообщений и перенаправит все операции в этот поток по умолчанию.

Но вы можете переопределить это поведение, указав экземпляр ISynchronizeInvoke вручную в конструкторе DdeClient. Затем библиотека будет использовать любой поток, в котором размещен экземпляр ISynchronizeInvoke, для всех своих операций DDE. Все экземпляры Form и Control реализуют ISynchronizeInvoke, поэтому достаточно просто указать библиотеке использовать основной поток пользовательского интерфейса.

Dim client As DdeClient = New DdeClient("ServerApplication", "Bid", yourForm)

Если вы скажете библиотеке использовать ваш экземпляр Form, тогда обработчики событий Advise будут выполняться в том же потоке, в котором находится Form; поток пользовательского интерфейса.

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


1 В нем также есть прискорбное требование соприкосновения нитей, которое сделало работу с сборщиком мусора настоящей болью.

0 голосов
/ 10 мая 2011

Реальность;) DDE работает медленно, графика работает медленно.Не делайте их в одном потоке.

Попробуйте это:

  • Создайте второй поток, который обрабатывает DDE, ставит в очередь элементы.
  • Затем поток диаграммы извлекаетобновляет и рисует их.

Теперь, вот вам и точка:

  • ТОЛЬКО поток пользовательского интерфейса может изменять элемент управления диаграммы.Да, отстой.Нет, не подлежит обсуждению.- старое правило пользовательского интерфейса с незапамятных времен.
  • Потоки нуждаются в блокировке;)
...