我知道在UI线程中调用Task.Wait
是不好的。它导致僵局。请参阅
Constructor invoke async method
Await, and UI, and deadlocks! Oh my!
请使用以下代码:
public MainPage()
{
this.InitializeComponent();
step0();
step1();
}
private async Task step0()
{
await Task.Delay(5000);
System.Diagnostics.Debug.WriteLine("step 0");
}
private async Task step1()
{
await Task.Delay(3000);
System.Diagnostics.Debug.WriteLine("step 1");
}
}
如何确保在“步骤1”之前始终打印“步骤0”?使用Task.Wait
会导致死锁。 这是Windows应用商店应用
答案 0 :(得分:8)
您可以使用Task.ContinueWith
将任务链接在一起,以便它们按顺序发生。
public MainPage()
{
this.InitializeComponent();
step0().ContinueWith(t => step1());
}
此外,阿列克谢的评论是正确的。 Task.Wait
将阻止 UI线程。死锁是另一回事。
答案 1 :(得分:5)
您不能拥有async
构造函数,句点。
所以无论你做什么,你都需要处理构造函数返回而没有完成async
初始化的情况。
有几种方法可以解决这个问题。如果“步骤”正在加载资源,那么您可以执行以下操作(使用AsyncLazy
type from my blog,Stephen Toub's blog或我的AsyncEx library - 它们几乎相同):
private readonly AsyncLazy<MyResource> resource;
public MainPage()
{
resource = new AsyncLazy<MyResource>(async () =>
{
var a = await step0();
var b = await step1();
return new MyResource(a, b); // or whatever
});
resource.Start(); // start step0
}
public async Task MethodThatNeedsResource()
{
var r = await resource; // ensure step1 is complete before continuing
}
也可以使用async void
方法或ContinueWith
执行此操作,但您必须仔细考虑使用这些方法进行错误处理。
AsyncLazy
方法会捕获错误,并在执行await resource
时提升错误。async void
方法会立即将错误抛给SynchronizationContext
。ContinueWith
方法会默默地忽略所有错误。无论您采取哪种方法,我建议在UI中通知初始化正在进行中。 (作为旁注,我认为所有这些应该进入ViewModel或Model类而不是MainPage
)。