Đây có thể là TL; DR đối với nhiều người, nhưng, tôi nghĩ so sánh awaitvới BackgroundWorkergiố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/ awaitlà 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 usingmà không có async/ await.
Nhưng, bạn sẽ không làm điều gì đó như thế với BackgroundWorker. BackgroundWorkerthườ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 đó, TaskSchedulerviệc tạo chủ đề cho bạn (giả sử là mặc định TaskScheduler) và có thể sử dụng awaitnhư 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 likecá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/ awaitvà 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, RunWorkerCompletedvà ProgressChangedxử 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 awaitvà 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 BackgroundWorkernhư 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