นี่น่าจะเป็น TL; DR สำหรับหลาย ๆ คน แต่ฉันคิดว่าการเปรียบเทียบawaitกับBackgroundWorkerนั้นเหมือนกับการเปรียบเทียบแอปเปิ้ลและส้มและความคิดของฉันเกี่ยวกับสิ่งต่อไปนี้:
BackgroundWorkerมีวัตถุประสงค์เพื่อสร้างแบบจำลองงานเดียวที่คุณต้องการที่จะดำเนินการในพื้นหลังในเธรดพูลเธรด async/ awaitเป็นไวยากรณ์สำหรับการรอการดำเนินการแบบอะซิงโครนัสแบบอะซิงโครนัส การดำเนินการเหล่านั้นอาจใช้หรือไม่ใช้เธรดพูลเธรดหรือแม้แต่ใช้เธรดอื่นก็ได้ ดังนั้นพวกมันคือแอปเปิ้ลและส้ม
ตัวอย่างเช่นคุณสามารถทำสิ่งต่อไปนี้ด้วยawait:
using (WebResponse response = await webReq.GetResponseAsync())
{
using (Stream responseStream = response.GetResponseStream())
{
int bytesRead = await responseStream.ReadAsync(buffer, 0, buffer.Length);
}
}
แต่คุณอาจไม่เคยทำแบบนั้นในคนทำงานเบื้องหลังคุณอาจทำสิ่งนี้ใน. 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);
ขอให้สังเกต disjointness ของการกำจัดเมื่อเทียบระหว่างสองไวยากรณ์และวิธีการที่คุณไม่สามารถใช้usingโดยไม่ต้อง/asyncawait
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();
ไม่มีอะไรจริงๆที่คุณสามารถใช้ async / รอด้วยBackgroundWorkerกำลังสร้างเธรดให้คุณ
ตอนนี้คุณสามารถใช้ 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);
ในกรณีนี้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"
ในความเห็นของฉันการเปรียบเทียบที่สำคัญคือคุณกำลังรายงานความคืบหน้าหรือไม่ ตัวอย่างเช่นคุณอาจมีสิ่ง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();
แต่คุณจะไม่จัดการกับสิ่งนี้เพราะคุณต้องลากและวางส่วนประกอบของผู้ทำงานเบื้องหลังลงบนพื้นผิวการออกแบบของฟอร์ม - สิ่งที่คุณไม่สามารถทำได้ด้วยasync/ awaitและTask... เช่นคุณชนะ ' ไม่สร้างวัตถุด้วยตนเองตั้งค่าคุณสมบัติและตั้งค่าตัวจัดการเหตุการณ์ คุณต้องการเพียงกรอกในร่างกายของDoWork, RunWorkerCompletedและProgressChangedจัดการเหตุการณ์
หากคุณ "แปลง" เป็น 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"
หากไม่มีความสามารถในการลากส่วนประกอบไปยังพื้นผิว Designer มันขึ้นอยู่กับผู้อ่านว่าจะเลือก "ดี" จริงหรือไม่ แต่สำหรับฉันแล้วการเปรียบเทียบระหว่างawaitและBackgroundWorkerไม่ว่าคุณจะสามารถรอวิธีการในตัวStream.ReadAsyncได้หรือไม่ เช่นถ้าคุณใช้ตามที่ตั้งใจไว้ก็อาจจะยากที่จะเปลี่ยนไปใช้BackgroundWorkerawait
ความคิดอื่น ๆ : http://jeremybytes.blogspot.ca/2012/05/backgroundworker-component-im-not-dead.html