1

У меня есть однопоточная программа, которая выполняет сложные, трудоемкие вычисления и сообщает о прогрессе.Многопоточный C# для гибкого графического интерфейса с комплексными вычислениями фона - async/await, TPL или оба?

метод
private void BtnExecute_Click() 
    { 
     ComplexCalculation(Object1); 
     ComplexCalculation(Object2); 
     ComplexCalculation(Object3); 
    } 

ComplexCalculation выглядит следующим образом:

private void ComplexCalculation(Object MyObject) 
{ 
    (...do some time consuming operation on MyObject...); 
    WriteToTextboxGUI("50% Complete" + MyObject.Name); 
    (...do another time consuming operation on MyObject...); 
    WriteToTextboxGUI("100% Complete" + MyObject.Name); 
} 

В приведенном выше коде, метод WriteToTextboxGUI(string) обновляет текстовое поле на GUI с прогрессом.

Я ищу, чтобы использовать многопоточный подход, чтобы графический интерфейс оставался отзывчивым при выполнении сложных вычислений. Я довольно много читал о BackgroundWorker и Threads, а затем, как это было упрощено/улучшено, когда Task и TPL вышли на сцену с .Net 4.0, и теперь, как Async и Await прибыли с .Net 4.5, и хотел бы знать, если эти более новые технологии могут позволить мне переписать мое заявление (в относительно простого кода), так что он может:

  • использование нескольких потоков одновременно для выполнения сложных расчетов
  • отчета о прогрессе в мой GUI как и раньше
  • Поддерживающий гибкий графический интерфейс по всему диапазону

Может ли кто-нибудь указать мне в направлении простого решения, которое бы удовлетворяло этим трем критериям?

P.S. Это приложение не будет работать на сервере, оно будет работать в WPF на рабочем столе.

+0

почему бы не просто использовать фоновый рабочий? –

+0

Будет ли BackgroundWorker инициировать поток для каждой из трех сложных задач, так что все три могут выполняться одновременно? – Caustix

+0

3 фоновых работника могли бы .... –

ответ

7

Я рекомендую вам использовать IProgress<T> для отчетов о ходе работы и Task.Run для запуска фоновых задач. Недавно я закончил серию блога, показывающую, что Task.Run is superior to BackgroundWorker.

В вашем случае:

private sealed class ComplexCalculationProgress 
{ 
    public string Name { get; set; } 
    public int PercentComplete { get; set; } 
} 

private void ComplexCalculation(Object MyObject, IProgress<ComplexCalculationProgress> progress) 
{ 
    (...do some time consuming operation on MyObject...); 
    if (progress != null) 
    progress.Report(new ComplexCalculationProgress { Name = MyObject.Name, PercentComplete = 50 }); 
    (...do another time consuming operation on MyObject...); 
    if (progress != null) 
    progress.Report(new ComplexCalculationProgress { Name = MyObject.Name, PercentComplete = 100 }); 
} 

Обратите внимание, что поскольку ваша фоновая работа уже не вызывает WriteToTextboxGUI, он не имеет лучшее разделение проблем.Вы обнаружите, что дизайн IProgress<T> способствует лучшему дизайну в вашем собственном коде.

Вы можете назвать его (с помощью простого параллелизм), как, например:

private async void BtnExecute_Click() 
{ 
    var progress = new Progress<ComplexCalculationProgress>(update => 
    { 
    WriteToTextboxGUI(update.PercentComplete + "% Complete " + update.Name); 
    }); 
    await Task.WhenAll(
    Task.Run(() => ComplexCalculation(Object1, progress)), 
    Task.Run(() => ComplexCalculation(Object2, progress)), 
    Task.Run(() => ComplexCalculation(Object3, progress)) 
); 
} 

В качестве альтернативы, вы можете легко использовать «реальный» параллелизм:

private async void BtnExecute_Click() 
{ 
    var progress = new Progress<ComplexCalculationProgress>(update => 
    { 
    WriteToTextboxGUI(update.PercentComplete + "% Complete " + update.Name); 
    }); 
    var objects = new[] { Object1, Object2, Object3 }; 
    await Task.Run(() => 
     Parallel.ForEach(objects, o => ComplexCalculation(o, progress)) 
); 
} 
+0

Спасибо за это. Я также читаю ваш блог, с которым вы связались, что я считаю действительно отличным. – Caustix

0

Работники фона могут делать все это легко.

Использование нескольких потоков одновременно выполнять сложные вычисления

Использовать новый фон рабочий для каждого расчета.

Доклад о ходе моей GUI, как и прежде

Использование WorkerReportsProgress = True, с помощью метода ReportProgress() и ProgressChanged события.

Поддерживать отзывчивый GUI на протяжении

Yep.

Смежные вопросы