C# 异步/等待 vs BackgroundWorker
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12414601/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Async/await vs BackgroundWorker
提问by Tom
In the past few days I have tested the new features of .net 4.5 and c# 5.
这几天我测试了.net 4.5和c#5的新特性。
I like its new async/await features. Earlier I had used BackgroundWorkerto handle longer processes in the background with responsive UI.
我喜欢它的新 async/await 特性。早些时候,我使用BackgroundWorker通过响应式 UI 在后台处理更长的进程。
My question is: after having these nice new features, when should I use async/await and when a BackgroundWorker? Which are the common scenarios for both?
我的问题是:在拥有这些不错的新功能之后,我应该何时使用 async/await 以及何时使用BackgroundWorker?两者的常见场景是什么?
采纳答案by Servy
async/await is designed to replace constructs such as the BackgroundWorker. While you certainly canuse it if you want to, you should be able to use async/await, along with a few other TPL tools, to handle everything that's out there.
async/await 旨在替换诸如BackgroundWorker. 虽然您当然可以根据需要使用它,但您应该能够使用 async/await 以及其他一些 TPL 工具来处理所有存在的问题。
Since both work, it comes down to personal preference as to which you use when. What is quicker for you? What is easier for youto understand?
由于两者都有效,这归结为您何时使用的个人偏好。什么对你来说更快?什么是更容易为你理解吗?
回答by TommyN
This is a good introduction: http://msdn.microsoft.com/en-us/library/hh191443.aspxThe Threads section is just what you are looking for:
这是一个很好的介绍:http: //msdn.microsoft.com/en-us/library/hh191443.aspx线程部分正是您要查找的内容:
Async methods are intended to be non-blocking operations. An await expression in an async method doesn't block the current thread while the awaited task is running. Instead, the expression signs up the rest of the method as a continuation and returns control to the caller of the async method.
The async and await keywords don't cause additional threads to be created. Async methods don't require multithreading because an async method doesn't run on its own thread. The method runs on the current synchronization context and uses time on the thread only when the method is active. You can use Task.Run to move CPU-bound work to a background thread, but a background thread doesn't help with a process that's just waiting for results to become available.
The async-based approach to asynchronous programming is preferable to existing approaches in almost every case. In particular, this approach is better than BackgroundWorker for IO-bound operations because the code is simpler and you don't have to guard against race conditions. In combination with Task.Run, async programming is better than BackgroundWorker for CPU-bound operations because async programming separates the coordination details of running your code from the work that Task.Run transfers to the threadpool.
异步方法旨在成为非阻塞操作。当等待的任务正在运行时,异步方法中的 await 表达式不会阻塞当前线程。相反,表达式将方法的其余部分注册为延续,并将控制权返回给异步方法的调用者。
async 和 await 关键字不会导致创建额外的线程。异步方法不需要多线程,因为异步方法不在自己的线程上运行。该方法在当前同步上下文上运行,并且仅当该方法处于活动状态时才在线程上使用时间。您可以使用 Task.Run 将受 CPU 限制的工作移至后台线程,但后台线程对仅等待结果可用的进程没有帮助。
几乎在所有情况下,基于异步的异步编程方法都优于现有方法。特别是,对于 IO 绑定操作,这种方法比 BackgroundWorker 更好,因为代码更简单,而且您不必防范竞争条件。与 Task.Run 结合使用,异步编程比 BackgroundWorker 更适合 CPU 密集型操作,因为异步编程将运行代码的协调细节与 Task.Run 传输到线程池的工作分开。
回答by Peter Ritchie
This is likely TL;DR for many, but, I think comparing awaitwith BackgroundWorkeris like comparing apples and oranges and my thoughts on this follow:
这可能是TL; DR为多,但是,我认为比较await有BackgroundWorker就是喜欢上了这后续比较苹果和桔子和我的想法:
BackgroundWorkeris meant to model a single task that you'd want to perform in the background, on a thread pool thread. async/awaitis a syntax for asynchronously awaiting on asynchronous operations. Those operations may or may not use a thread pool thread or even use any other thread. So, they're apples and oranges.
BackgroundWorker旨在对您希望在后台在线程池线程上执行的单个任务进行建模。 async/await是异步等待异步操作的语法。这些操作可能使用也可能不使用线程池线程,甚至使用任何其他线程。所以,它们是苹果和橙子。
For example, you can do something like the following with await:
例如,您可以执行以下操作await:
using (WebResponse response = await webReq.GetResponseAsync())
{
using (Stream responseStream = response.GetResponseStream())
{
int bytesRead = await responseStream.ReadAsync(buffer, 0, buffer.Length);
}
}
But, you'd likely never model that in a background worker, you'd likely do something like this in .NET 4.0 (prior to await):
但是,您可能永远不会在后台工作人员中进行建模,您可能会在 .NET 4.0(在 之前await)中执行以下操作:
webReq.BeginGetResponse(ar =>
{
WebResponse response = webReq.EndGetResponse(ar);
Stream responseStream = response.GetResponseStream();
responseStream.BeginRead(buffer, 0, buffer.Length, ar2 =>
{
int bytesRead = responseStream.EndRead(ar2);
responseStream.Dispose();
((IDisposable) response).Dispose();
}, null);
}, null);
Notice the disjointness of the disposal compared between the two syntaxes and how you can't use usingwithout async/await.
请注意两种语法之间比较的处理的不相交性以及如何在using没有async/ 的情况下使用await。
But, you wouldn't do something like that with BackgroundWorker. BackgroundWorkeris usually for modeling a single long-running operation that you don't want to impact the UI responsiveness. For example:
但是,你不会用BackgroundWorker. BackgroundWorker通常用于对单个长时间运行的操作进行建模,该操作不希望影响 UI 响应能力。例如:
worker.DoWork += (sender, e) =>
{
int i = 0;
// simulate lengthy operation
Stopwatch sw = Stopwatch.StartNew();
while (sw.Elapsed.TotalSeconds < 1)
++i;
};
worker.RunWorkerCompleted += (sender, eventArgs) =>
{
// TODO: do something on the UI thread, like
// update status or display "result"
};
worker.RunWorkerAsync();
There's really nothing there you can use async/await with, BackgroundWorkeris creating the thread for you.
真的没有什么可以使用 async/await 的,BackgroundWorker正在为您创建线程。
Now, you could use TPL instead:
现在,您可以改用 TPL:
var synchronizationContext = TaskScheduler.FromCurrentSynchronizationContext();
Task.Factory.StartNew(() =>
{
int i = 0;
// simulate lengthy operation
Stopwatch sw = Stopwatch.StartNew();
while (sw.Elapsed.TotalSeconds < 1)
++i;
}).ContinueWith(t=>
{
// TODO: do something on the UI thread, like
// update status or display "result"
}, synchronizationContext);
In which case the TaskScheduleris creating the thread for you (assuming the default TaskScheduler), and could use awaitas follows:
在这种情况下,TaskScheduler正在为您创建线程(假设默认TaskScheduler),并且可以使用await如下:
await Task.Factory.StartNew(() =>
{
int i = 0;
// simulate lengthy operation
Stopwatch sw = Stopwatch.StartNew();
while (sw.Elapsed.TotalSeconds < 1)
++i;
});
// TODO: do something on the UI thread, like
// update status or display "result"
In my opinion, a major comparison is whether you're reporting progress or not. For example, you might have a BackgroundWorker likethis:
在我看来,一个主要的比较是你是否报告进展。例如,您可能有一个BackgroundWorker like这样的:
BackgroundWorker worker = new BackgroundWorker();
worker.WorkerReportsProgress = true;
worker.ProgressChanged += (sender, eventArgs) =>
{
// TODO: something with progress, like update progress bar
};
worker.DoWork += (sender, e) =>
{
int i = 0;
// simulate lengthy operation
Stopwatch sw = Stopwatch.StartNew();
while (sw.Elapsed.TotalSeconds < 1)
{
if ((sw.Elapsed.TotalMilliseconds%100) == 0)
((BackgroundWorker)sender).ReportProgress((int) (1000 / sw.ElapsedMilliseconds));
++i;
}
};
worker.RunWorkerCompleted += (sender, eventArgs) =>
{
// do something on the UI thread, like
// update status or display "result"
};
worker.RunWorkerAsync();
But, you wouldn't deal with some of this because you'd drag-and-drop the background worker component on to the design surface of a form--something you can't do with async/awaitand Task... i.e. you won't manually create the object, set the properties and set the event handlers. you'd only fill in the body of the DoWork, RunWorkerCompleted, and ProgressChangedevent handlers.
但是,您不会处理其中的一些问题,因为您会将后台工作组件拖放到表单的设计表面上——这是您无法使用async/await和Task... t 手动创建对象、设置属性并设置事件处理程序。你只填写的身体DoWork,RunWorkerCompleted和ProgressChanged事件处理程序。
If you "converted" that to async/await, you'd do something like:
如果您将其“转换”为 async/await,您将执行以下操作:
IProgress<int> progress = new Progress<int>();
progress.ProgressChanged += ( s, e ) =>
{
// TODO: do something with e.ProgressPercentage
// like update progress bar
};
await Task.Factory.StartNew(() =>
{
int i = 0;
// simulate lengthy operation
Stopwatch sw = Stopwatch.StartNew();
while (sw.Elapsed.TotalSeconds < 1)
{
if ((sw.Elapsed.TotalMilliseconds%100) == 0)
{
progress.Report((int) (1000 / sw.ElapsedMilliseconds))
}
++i;
}
});
// TODO: do something on the UI thread, like
// update status or display "result"
Without the ability to drag a component on to a Designer surface, it's really up to the reader to decide which is "better". But, that, to me, is the comparison between awaitand BackgroundWorker, not whether you can await built-in methods like Stream.ReadAsync. e.g. if you were using BackgroundWorkeras intended, it could be hard to convert to use await.
由于无法将组件拖到 Designer 表面上,因此真正由读者决定哪个“更好”。但是,对我来说,这是和 之间的比较,await而BackgroundWorker不是您是否可以等待诸如Stream.ReadAsync. 例如,如果您BackgroundWorker按预期使用,则可能很难转换为 use await。
Other thoughts: http://jeremybytes.blogspot.ca/2012/05/backgroundworker-component-im-not-dead.html
其他想法:http: //jeremybytes.blogspot.ca/2012/05/backgroundworker-component-im-not-dead.html
回答by Gennady Vanin Геннадий Ванин
BackgroundWorkeris explicitly labeled as obsolete in .NET 4.5:
BackgroundWorker在 .NET 4.5 中被明确标记为已过时:
- in the book By Joseph Albahari, Ben Albahari "C# 5.0 in a Nutshell: The Definitive Reference"
- Stephen Cleary's answer to my question "Wasn't it .NET 4.0 TPL that made APM, EAP and BackgroundWorker asynchronous patterns obsolete?"
- 在Joseph Albahari 和 Ben Albahari 着的“C# 5.0 in a Nutshell: The Definitive Reference”一书中
- Stephen Cleary 对我的问题的回答“是不是 .NET 4.0 TPL 使 APM、EAP 和 BackgroundWorker 异步模式过时了?”
MSDN article "Asynchronous Programming with Async and Await (C# and Visual Basic)"tells:
MSDN 文章“使用 Async 和 Await(C# 和 Visual Basic)进行异步编程”讲述:
The async-based approach to asynchronous programming is preferable to existing approaches in almost every case. In particular, this approach is better than BackgroundWorkerfor IO-bound operationsbecause the code is simpler and you don't have to guard against race conditions. In combination with Task.Run, async programming is better than BackgroundWorkerfor CPU-bound operationsbecause async programming separates the coordination details of running your code from the work that Task.Runtransfers to the threadpool
几乎在所有情况下,基于异步的异步编程方法都优于现有方法。特别是,对于 IO 绑定操作,这种方法比BackgroundWorker更好,因为代码更简单,而且您不必防范竞争条件。与 Task.Run 结合使用,异步编程比BackgroundWorker 更适合 CPU 密集型操作,因为异步编程将运行代码的协调细节与Task.Run转移到线程池的工作分开
UPDATE
更新
- in response to @eran-otzap's comment:
"for IO-bound operations because the code is simpler and you don't have to guard against race conditions" What race conditions can occure , could you give an example ? "
- 回应@eran-otzap的评论:
“对于 IO-bound 操作,因为代码更简单,您不必防范竞争条件”可能发生哪些竞争条件,您能举个例子吗?”
This question should have been put as a separate post.
这个问题应该作为一个单独的帖子提出。
Wikipedia has a good explanation of racingconditions. The necessary part of it is multithreading and from the same MSDN article Asynchronous Programming with Async and Await (C# and Visual Basic):
维基百科对赛车条件有很好的解释。它的必要部分是多线程,来自同一篇 MSDN 文章Asynchronous Programming with Async and Await (C# and Visual Basic):
Async methods are intended to be non-blocking operations. An await expression in an async method doesn't block the current thread while the awaited task is running. Instead, the expression signs up the rest of the method as a continuation and returns control to the caller of the async method.
The async and await keywords don't cause additional threads to be created. Async methods don't require multithreading because an async method doesn't run on its own thread. The method runs on the current synchronization context and uses time on the thread only when the method is active. You can use Task.Run to move CPU-bound work to a background thread, but a background thread doesn't help with a process that's just waiting for results to become available.
The async-based approach to asynchronous programming is preferable to existing approaches in almost every case. In particular, this approach is better than BackgroundWorker for IO-bound operations because the code is simpler and you don't have to guard against race conditions. In combination with Task.Run, async programming is better than BackgroundWorker for CPU-bound operations because async programming separates the coordination details of running your code from the work that Task.Run transfers to the threadpool
异步方法旨在成为非阻塞操作。当等待的任务正在运行时,异步方法中的 await 表达式不会阻塞当前线程。相反,表达式将方法的其余部分注册为延续,并将控制权返回给异步方法的调用者。
async 和 await 关键字不会导致创建额外的线程。异步方法不需要多线程,因为异步方法不在自己的线程上运行。该方法在当前同步上下文上运行,并且仅当该方法处于活动状态时才在线程上使用时间。您可以使用 Task.Run 将受 CPU 限制的工作移至后台线程,但后台线程对仅等待结果可用的进程没有帮助。
几乎在所有情况下,基于异步的异步编程方法都优于现有方法。特别是,对于 IO 绑定操作,这种方法比 BackgroundWorker 更好,因为代码更简单,而且您不必防范竞争条件。与 Task.Run 结合使用,异步编程比 BackgroundWorker 更适合 CPU 密集型操作,因为异步编程将运行代码的协调细节与 Task.Run 转移到线程池的工作分开
That is, "The async and await keywords don't cause additional threads to be created".
也就是说,“async 和 await 关键字不会导致创建额外的线程”。
As far as I can recall my own attempts when I was studying this article a year ago, if you have run and played with code sample from the same article, you could bump in situation that its non-async versions (you could try to convert it to yourself) block indefinitely!
就我一年前研究这篇文章时我自己的尝试而言,如果您运行并使用了同一篇文章中的代码示例,您可能会遇到它的非异步版本的情况(您可以尝试转换给自己)无限期阻止!
Also, for concrete examples you could search this site. Here are some example:
此外,有关具体示例,您可以搜索此站点。下面是一些例子:

