Đây có thể là TL; DR đối với nhiều người, nhưng, tôi nghĩ so sánh await
với BackgroundWorker
giống như so sánh táo và cam và suy nghĩ của tôi về điều này như sau:
BackgroundWorker
được dùng để mô hình hóa một tác vụ duy nhất mà bạn muốn thực hiện trong nền, trên một chuỗi nhóm luồng. async
/ await
là một cú pháp để chờ không đồng bộ trên các hoạt động không đồng bộ. Những hoạt động đó có thể hoặc không thể sử dụng một chuỗi nhóm luồng hoặc thậm chí sử dụng bất kỳ luồng nào khác . Vì vậy, chúng là táo và cam.
Ví dụ: bạn có thể làm một cái gì đó như sau với await
:
using (WebResponse response = await webReq.GetResponseAsync())
{
using (Stream responseStream = response.GetResponseStream())
{
int bytesRead = await responseStream.ReadAsync(buffer, 0, buffer.Length);
}
}
Nhưng, bạn có thể không bao giờ mô hình hóa rằng trong một nhân viên nền, bạn có thể sẽ làm một cái gì đó như thế này trong .NET 4.0 (trước đó 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);
Lưu ý sự khác biệt của việc xử lý được so sánh giữa hai cú pháp và cách bạn không thể sử dụng using
mà không có async
/ await
.
Nhưng, bạn sẽ không làm điều gì đó như thế với BackgroundWorker
. BackgroundWorker
thường là để mô hình hóa một hoạt động dài hạn mà bạn không muốn tác động đến khả năng đáp ứng của UI. Ví dụ:
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();
Thực sự không có gì ở đó bạn có thể sử dụng async / await với, BackgroundWorker
đang tạo chủ đề cho bạn.
Bây giờ, bạn có thể sử dụng TPL thay thế:
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);
Trong trường hợp đó, TaskScheduler
việc tạo chủ đề cho bạn (giả sử là mặc định TaskScheduler
) và có thể sử dụng await
như sau:
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"
Theo tôi, một so sánh chính là liệu bạn có báo cáo tiến độ hay không. Ví dụ: bạn có thể có một BackgroundWorker like
cái này:
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();
Tuy nhiên, bạn sẽ không giải quyết một số vấn đề này vì bạn kéo và thả thành phần nhân viên nền trên bề mặt thiết kế của biểu mẫu - điều bạn không thể làm với async
/ await
và Task
... tức là bạn đã thắng ' Tạo thủ công đối tượng, đặt thuộc tính và đặt trình xử lý sự kiện. bạn chỉ muốn điền thông tin vào cơ thể của DoWork
, RunWorkerCompleted
và ProgressChanged
xử lý sự kiện.
Nếu bạn "chuyển đổi" thành async / await, bạn sẽ làm một cái gì đó như:
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"
Không có khả năng kéo một thành phần lên bề mặt Nhà thiết kế, người đọc thực sự quyết định cái nào là "tốt hơn". Nhưng, điều đó, với tôi, là sự so sánh giữa await
và BackgroundWorker
, không phải là liệu bạn có thể chờ đợi các phương thức tích hợp như thế nào không Stream.ReadAsync
. ví dụ: nếu bạn đang sử dụng BackgroundWorker
như dự định, có thể khó chuyển đổi sang sử dụng await
.
Những suy nghĩ khác: http://jeremybytes.blogspot.ca/2012/05/backgroundworker-component-im-not-dead.html