Проблема с приложением WPF и медленным откликом графического интерфейса - PullRequest
3 голосов
/ 18 марта 2011

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

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

Я хочу поделиться с вами своей идеей, в которой может быть проблема, и мне хотелось бы услышать, что вы об этом думаете, имеет ли это какой-то смысл или нет.

Чтобы получить данные с сервера, приложение использует 7 потоков (это делается в основном из-за логики приложения, поэтому не обращайте слишком много внимания на то, почему 7, а не только один ...) теперь каждый поток создается путем вызова метода CreateThreadForTask ()

public void StartAllThreads()
{
    this.CreateThreadForTask(Tasks.Task1);
    this.CreateThreadForTask(Tasks.Task2);
    this.CreateThreadForTask(Tasks.Task3);
    this.CreateThreadForTask(Tasks.Task4);
    this.CreateThreadForTask(Tasks.Task5);
    this.CreateThreadForTask(Tasks.Task6);
    this.CreateThreadForTask(Tasks.Task7);
}

public void CreateThreadForTask(Tasks task)
{
    ... // this part of the code is not important

    //! Initialize and start timer
    timer = null;
    timer = new DispatcherTimer();
    timer.Tick += new EventHandler(RunMainSyncForTask);
    timer.Start();  
}

public void RunMainSyncForTask(object s, EventArgs e)
{
    int sec = int.Parse(AppSettings.GetSetting("syncInterval"));
    timer.Interval = new TimeSpan(0, 0, sec);

    //threadCaller is a background worker
    threadCaller = InitializeThread();
    threadCaller.DoWork += DoWorkEventHandler(StartSync);
    threadCaller.RunWorkerAsync();
}

Когда я отлаживал код, я заметил, что все потоки созданы с использованием DispatcherTimer; я думаю, что приложение создает 7 DispatcherTimer's и связывает событие Tick таймеров с методом RunMainSyncForTask (), который внутри создает фонового работника, который получает данные с сервера и сохраняет эти данные в локальной базе данных.

Теперь это было взято из MSDN

DispatcherTimer переоценивается в верхней части каждого цикла Dispatcher.

Таймеры не гарантированно будут работать точно, когда наступит временной интервал, но они гарантированно не выполнятся до того, как временной интервал наступит. Это связано с тем, что операции DispatcherTimer помещаются в очередь Dispatcher, как и другие операции. Время выполнения операции DispatcherTimer зависит от других заданий в очереди и их приоритетов.

Итак, исходя из этого, я считаю, что приложение спамит потоки каждый раз, когда таймер выполняет тиковое событие, и это делается 7 раз одновременно; и все эти операции, из-за природы DispatcherTimer, добавляются в очередь Dispatcher, что замедляет реакцию GUI из-за занятости Dispatcher.

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

Так что, если вы можете поделиться некоторыми внутренностями по этому поводу, я буду признателен.

Спасибо.

1 Ответ

1 голос
/ 18 марта 2011

Вы получаете 90-95% ЦП, потому что вы установили форму занятого ожидания через сумасшедшую сеть потоковых вызовов.

Если вы используете эту StartSync логику для публикации статусауведомления или получить данные обратно в графический интерфейс, вы прыгаете через много обручей.Если вы используете .Net 4.0, вам следует переключиться на Task Parallel Library и позволить фреймворку обрабатывать все это за вас.Он также поддерживает постепенную отмену и т. Д.

Если вы не хотите использовать TPL, я бы предложил вместо этого передать Window s Dispatcher (используйте обычные подозрения: Invoke или BeginInvoke) или SynchronizationContext (асинхронно с Post, синхронно с Send) для отдельных задач для использования для этих задач, которые должны быть выполнены в графическом интерфейсе.

...