Gen*_*нин 19 c# wpf backgroundworker task-parallel-library async-await
我有2种C#WPF应用程序项目:
所有这些都应该产生2-10个长时间运行(天)的过程,这些过程可以被用户取消和重新启动.
我有兴趣遵循最佳设计实践.首先,现在,我有兴趣消除BackgroundWorker
使用的歧义,但我希望,我的问题应该对其他异步模式有效.
我看到(矛盾)并发的观点
异步模式:
A).NET 4.5使它们过时了
"基于异步的异步编程方法几乎在所有情况下都优于现有方法.特别是,对于IO绑定操作,这种方法优于BackgroundWorker,因为代码更简单,您不必防范竞争条件.与Task.Run结合使用,异步编程优于 BackgroundWorker用于CPU绑定操作,因为异步编程将运行代码的协调细节与Task.Run传输到线程池的工作分开"
BackgroundWorker
)在.NET 4.5中没有过时 我仍有疑问:
如果它们在.NET 4.5中已经过时,为什么它们在.NET 4.0中不会过时?
2A)我是否错误地理解.NET 4.0新功能在.NET 4.0中仍然"易于"实现/重现?
Pet*_*hie 15
我通常建议Task
和/或await
使用.NET 4.5.但是Task
&BGW有2种截然不同的情景.任务适用于可以链接到延续的一般短异步任务,并且等待擅长隐式编组回UI线程的任务.BGW适用于单个长操作,不会影响UI的响应性.您可以将BGW拖放到设计图面上,然后双击以创建事件处理程序.您不必处理LongRunning
或者ConfigureAwait
如果您不想编组到另一个线程.许多人发现BGW的进展比较容易IProgress<T>
.
以下是在"冗长操作"场景中使用两者的一些示例:
由于该问题特别提到了.NET 4.0,因此以下是使用a Task
进行冗长操作同时向UI提供进度的简单代码:
startButton.Enabled = false;
var task = Task.Factory.
StartNew(() =>
{
foreach (var x in Enumerable.Range(1, 10))
{
var progress = x*10;
Thread.Sleep(500); // fake work
BeginInvoke((Action) delegate {
progressBar1.Value = progress;
});
}
}, TaskCreationOptions.LongRunning)
.ContinueWith(t =>
{
startButton.Enabled = true;
progressBar1.Value = 0;
});
Run Code Online (Sandbox Code Playgroud)
类似的代码BackgroundWorker
可能是:
startButton.Enabled = false;
BackgroundWorker bgw = new BackgroundWorker { WorkerReportsProgress = true };
bgw.ProgressChanged += (sender, args) =>
{ progressBar1.Value = args.ProgressPercentage; };
bgw.RunWorkerCompleted += (sender, args) =>
{
startButton.Enabled = true;
progressBar1.Value = 0;
};
bgw.DoWork += (sender, args) =>
{
foreach (var x in Enumerable.Range(1, 10))
{
Thread.Sleep(500);
((BackgroundWorker)sender).ReportProgress(x * 10);
}
};
bgw.RunWorkerAsync();
Run Code Online (Sandbox Code Playgroud)
现在,如果您使用的是.NET 4.5,则可以使用Progress<T>
而不是BeginInvoke
使用Task
.从4.5开始,使用await
可能更具可读性:
startButton.Enabled = false;
var pr = new Progress<int>();
pr.ProgressChanged += (o, i) => progressBar1.Value = i;
await Task.Factory.
StartNew(() =>
{
foreach (var x in Enumerable.Range(1, 10))
{
Thread.Sleep(500); // fake work
((IProgress<int>) pr).Report(x*10);
}
}, TaskCreationOptions.LongRunning);
startButton.Enabled = true;
progressBar1.Value = 0;
Run Code Online (Sandbox Code Playgroud)
使用Progress<T>
意味着代码没有耦合到特定的UI框架(即调用BeginInvoke
),其方式与BackgroundWorker
促进与特定UI框架分离的方式大致相同.如果您不在乎,那么您不需要介绍使用的额外复杂性Progress<T>
至于LongRunning
斯蒂芬·图布说:"你通常只使用LongRunning,如果你通过性能测试发现没有使用它会导致其他工作处理的长时间延迟"所以,如果你发现你需要使用它,那么你使用它 - 增加的分析或只是总是添加LongRunning
参数的"复杂性" .不使用LongRunning意味着用于长时间运行操作的线程池线程将无法用于其他更短暂的任务,并且可能会强制线程池在启动另一个线程时延迟启动其中一个临时任务(至少是第二).
框架中没有任何属性明确表示BGW(或EAP或APM)已被弃用.因此,由您来决定这些东西何时何地"过时".BGW特别总是有一个非常具体的使用场景仍然适用于它.你在.NET 4.0和4.5中有相当不错的选择; 但我并不认为BGW是"过时的".
我并不是说总是使用BackgroundWorker
,我只是说在你自动弃用BackgroundWorker之前想一想,在某些情况下它可能是一个更好的选择.
Ste*_*ary 14
我认为这些模式(特别是APM,EAP和BGW)在.NET 4.5中已经过时了.的组合async
与Task.Run
在各方面都优于BGW.事实上,我刚刚在我的博客上开始了一个系列节目,我将比较BGW Task.Run
并展示它在各种情况下的繁琐程度; 也有一些情况下,它只是稍微比较繁琐,但也有它的其他情形多比较繁琐.
现在,它们是否在.NET 4.0中已经过时完全是另一个问题.在您的其他帖子中,您正在讨论使用VS2010开发.NET 4.0 ,因此不支持backport Microsoft.Bcl.Async
.在这种情况下,APM和EAP都不能被视为过时的IMO.在这个平台上,您可以考虑Task.Factory.StartNew
作为BGW的替代品,但BGW在进度报告和自动线程编组其进度和完成事件方面确实具有一些优势.
更新:我最近更新了我的一篇旧博客文章,在那里我讨论了各种后台操作的实现.在那篇文章中,当我谈到"任务(异步方法)"时,我的意思是使用Task
所有.NET 4.5 async
支持Task.Run
等."任务(任务并行库)"部分正在评估Task
它在.NET 4.0中的存在.
归档时间: |
|
查看次数: |
3980 次 |
最近记录: |