Запуск нескольких фоновых задач в приложении WPF - задержка обновления пользовательского интерфейса - PullRequest
0 голосов
/ 21 февраля 2020

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

Сценарий

В приложении WPF мы будем вызывать один и тот же API тысячи раз с разными переданными параметрами. Нам нужно собрать все ответы и что-то сделать.

Пример кода

List<Task> tasks = new List<Task>();

for (int i = 1; i <= iterations; i++)
{
   Task t = SampleTask(new SampleTaskParameterCollection { TaskId = i, Locker = locker, MinSleep = minSleep, MaxSleep = maxSleep });
   tasks.Add(t);
}

Task.WhenAll(tasks);
private void SampleTask(SampleTaskParameterCollection parameters)
{
   int sleepTime = rnd.Next(parameters.MinSleep, parameters.MaxSleep);
   Thread.Sleep(sleepTime);

   Application.Current.Dispatcher.BeginInvoke(new Action(() =>
   {
      lock (parameters.Locker)
      {
         ProgressBar1.Value = ProgressBar1.Value + 1;
         LogTextbox.Text = LogTextbox.Text + Environment.NewLine + "Task " + parameters.TaskId + " slept for " + sleepTime + "ms and has now completed.";
      }
      LogTextbox.ScrollToEnd();

      if (ProgressBar1.Maximum == ProgressBar1.Value)
      {
         RunSlowButton.IsEnabled = true;
         RunFastButton.IsEnabled = true;
         ProgressBar1.Value = 0;
      }
   }), System.Windows.Threading.DispatcherPriority.Send);
}

Текущий репо находится на GitHub, Посмотрите на SimpleWindow.

1 Ответ

1 голос
/ 21 февраля 2020

Не создавайте тысячи задач - это вызовет огромные проблемы с производительностью.

Вместо этого используйте что-то вроде Parallel.For(), чтобы ограничить количество одновременно запускаемых задач; например:

Parallel.For(1,
    iterations + 1,
    (index) =>
    {
        SampleTask(new SampleTaskParameterCollection { TaskId = index, Locker = locker, MinSleep = minSleep, MaxSleep = maxSleep });
    });

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

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

Однако учтите, что во избежание проблем с потоками вы бы необходимо использовать Interlocked.Increment() (или какую-либо другую блокировку) при увеличении и проверке значения счетчика. Вам также необходимо убедиться, что вы обновили интерфейс в последний раз, когда вся работа будет выполнена.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...