我有一个单线程程序,它执行复杂,耗时的计算并报告这些程序的进度。
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上的文本框。
我正在寻求采用多线程方法,以便在执行复杂计算时GUI保持响应。我已经阅读了很多关于BackgroundWorker
和Threads
的内容,然后在Task
和TPL与.Net 4.0一起进入现场时如何简化/改进了这一点,现在又如何Async
和Await
已经与.Net 4.5一起到了,并且想知道这些更新的技术是否允许我重新编写我的应用程序(使用相对简单的代码),以便它可以:
任何人都可以指出一个满足这三个标准的简单解决方案吗?
P.S。此应用程序不会在服务器上运行,它将在桌面上的WPF中运行。
答案 0 :(得分: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))
);
}
或者,您可以轻松使用&#34; real&#34;并行:
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))
);
}
答案 1 :(得分:0)
后台工作人员可以轻松完成所有这些工作。
同时使用多个线程执行复杂的计算
为每次计算使用新的后台工作程序。
像以前一样向我的GUI报告进度
使用ReportReportsProgress = True,使用ReportProgress()方法和ProgressChanged事件。
在整个
中维护响应式GUI
是的。