นี่น่าจะเป็น 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
โดยไม่ต้อง/async
await
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
ได้หรือไม่ เช่นถ้าคุณใช้ตามที่ตั้งใจไว้ก็อาจจะยากที่จะเปลี่ยนไปใช้BackgroundWorker
await
ความคิดอื่น ๆ : http://jeremybytes.blogspot.ca/2012/05/backgroundworker-component-im-not-dead.html