DispatcherTimer, который запускает событие Tick в потоке пользовательского интерфейса, - это то, что считается таймером с низким разрешением или с низкой точностью, поскольку его интервал фактически означает «тик не раньше x с момента последнего тика». Если поток пользовательского интерфейса занят чем-либо (обработка ввода, обновление графика и т. Д.), То это приведет к задержке событий таймера. Кроме того, наличие большого числа элементов DispatcherTimer, тикающих в потоке пользовательского интерфейса с очень малыми интервалами, также замедлит скорость отклика вашего приложения, поскольку во время вызова события Tick приложение не может отвечать на ввод.
Итак, как вы заметили, для частой обработки данных вы должны перейти в фоновый поток. Но есть предостережения. Тот факт, что вы сейчас не наблюдаете коррупцию или другие ошибки, может быть чисто случайным. Если список изменяется в фоновом потоке в то время, когда поток переднего плана пытается прочитать из него, вы в конечном итоге потерпите крах (если вам повезет) или увидите поврежденные данные.
В вашем примере у вас есть комментарий, который гласит: «Нет необходимости обновлять график, он обновляется автоматически». Это заставляет меня задуматься, откуда диаграмма узнает, что вы изменили коллекцию datapoints
? List<T>
не вызывает события при его изменении. Если бы вы использовали ObservableCollection<T>
, я бы отметил, что каждый раз, когда вы удаляете / добавляете точку, вы потенциально обновляете график, что может замедлять процесс.
Но если вы на самом деле используете List<T>
, тогда должно быть что-то еще (возможно, другой таймер?), Который обновляет график. Может быть, сам элемент управления диаграммы имеет встроенный механизм автообновления?
В любом случае, проблема немного сложная , но не совсем новая . Есть способы, которыми вы могли бы поддерживать коллекцию в фоновом потоке и связываться с ней из потока пользовательского интерфейса. Но чем быстрее обновляется ваш пользовательский интерфейс, тем больше вероятность того, что фоновый поток освободит блокировку.
Один из способов минимизировать это - использовать LinkedList<T>
вместо List<T>
. В конец LinkedList добавляется O (1), поэтому удаляется элемент. List<T>
необходимо сдвинуть все на единицу, когда вы удаляете элемент с самого начала. Используя LinkedList, вы можете заблокировать его в фоновом потоке (ах) и минимизировать время удержания блокировки. В потоке пользовательского интерфейса вам также необходимо получить такую же блокировку и либо скопировать список в массив, либо обновить диаграмму, пока блокировка удерживается.
Другим возможным решением будет буферизовать «порции» точек в фоновом потоке и опубликовать пакет из них в потоке пользовательского интерфейса с помощью Dispatcher.BeginInvoke, где вы сможете безопасно обновить коллекцию.