Task.Run
ผมอยากจะขอให้คุณอยู่กับความเห็นของคุณเกี่ยวกับสถาปัตยกรรมที่ถูกต้องเมื่อใช้ ฉันกำลังประสบกับความล้าหลัง UI ในแอปพลิเคชัน WPF .NET 4.5 ของเรา (ด้วยกรอบ Caliburn Micro)
โดยทั่วไปฉันกำลังทำ (ตัวอย่างโค้ดที่ง่ายมาก):
public class PageViewModel : IHandle<SomeMessage>
{
...
public async void Handle(SomeMessage message)
{
ShowLoadingAnimation();
// Makes UI very laggy, but still not dead
await this.contentLoader.LoadContentAsync();
HideLoadingAnimation();
}
}
public class ContentLoader
{
public async Task LoadContentAsync()
{
await DoCpuBoundWorkAsync();
await DoIoBoundWorkAsync();
await DoCpuBoundWorkAsync();
// I am not really sure what all I can consider as CPU bound as slowing down the UI
await DoSomeOtherWorkAsync();
}
}
จากบทความ / วิดีโอผมอ่าน / เลื่อยฉันรู้ว่าไม่จำเป็นต้องทำงานบนด้ายพื้นหลังและจะเริ่มต้นทำงานในพื้นหลังที่คุณจำเป็นต้องห่อด้วยรอคอยawait
async
Task.Run(async () => ... )
การใช้async
await
ไม่ได้บล็อก UI แต่ยังคงทำงานอยู่บนเธรด UI ดังนั้นจึงทำให้มันล้าหลัง
ที่ที่ดีที่สุดในการวาง Task.Run อยู่ที่ไหน
ฉันควรจะแค่
ตัดการเรียกภายนอกเนื่องจากการทำงานของเธรดน้อยกว่าสำหรับ. NET
หรือฉันควรจะห่อเฉพาะวิธีที่ผูกกับ CPU ที่ทำงานอยู่ภายใน
Task.Run
เพราะจะทำให้มันสามารถนำกลับมาใช้ใหม่ได้สำหรับที่อื่น ๆ ? ฉันไม่แน่ใจว่าที่นี่หากเริ่มทำงานกับเธรดพื้นหลังที่อยู่ในแกนลึกเป็นความคิดที่ดี
โฆษณา (1) ทางออกแรกจะเป็นเช่นนี้:
public async void Handle(SomeMessage message)
{
ShowLoadingAnimation();
await Task.Run(async () => await this.contentLoader.LoadContentAsync());
HideLoadingAnimation();
}
// Other methods do not use Task.Run as everything regardless
// if I/O or CPU bound would now run in the background.
โฆษณา (2) ทางออกที่สองจะเป็นเช่นนี้:
public async Task DoCpuBoundWorkAsync()
{
await Task.Run(() => {
// Do lot of work here
});
}
public async Task DoSomeOtherWorkAsync(
{
// I am not sure how to handle this methods -
// probably need to test one by one, if it is slowing down UI
}
await Task.Run(async () => await this.contentLoader.LoadContentAsync());
await Task.Run( () => this.contentLoader.LoadContentAsync() );
AFAIK คุณไม่ได้อะไรโดยการเพิ่มเป็นครั้งที่สองawait
และภายในasync
และเนื่องจากคุณไม่ได้ผ่านพารามิเตอร์ช่วยลดความยุ่งยากมากขึ้นเล็กน้อยมาอยู่ที่Task.Run
await Task.Run( this.contentLoader.LoadContentAsync );