And*_*ord 0 c# async-await windows-phone-8 windows-store-apps
我正在将Windows Phone应用程序移植到Windows 8,我遇到了async/await问题.有一个类需要一段时间才能加载其所有数据.为了不阻止UI线程,加载在单独的任务/线程中完成.加载完成后,需要更新UI线程:
public class MyClass {
public MyClass() {
...
LoadData();
...
}
private async void LoadData() {
Debug.WriteLine("StartLoad: " + Environment.CurrentManagedThreadId);
await ReadDataAsync();
Debug.WriteLine("EndLoad: " + Environment.CurrentManagedThreadId);
UpdateUI();
}
private Task ReadDataAsync() {
return Task.Run(() => {
Debug.WriteLine("Reading: " + Environment.CurrentManagedThreadId);
...Read...
});
}
}
Run Code Online (Sandbox Code Playgroud)
在Windows Phone上,输出是这样的:
StartLoad:1
阅读:4
EndLoad:1
当我在Windows应用商店应用中执行相同的代码时,输出为:
StartLoad:1
阅读:4
EndLoad:4
在Windows Phone上,ThreadId是相同的,在等待Windows 8之后,await之后的ThreadId与await之前的不一样.这是与后台任务中相同的线程.由于这个UpdateUI()在错误的(非UI)线程中执行,应用程序崩溃...
这种不同行为的原因是什么?
..
编辑: 嗯,这很有趣:尽管在这两种情况下,进程都是从同一个线程(3)开始的,但问题只会在进程从App()构造函数启动时显示,而不是从OnLaunched启动时显示.知道为什么会这样吗?
sealed partial class App : Application {
public App() {
this.InitializeComponent();
this.Suspending += OnSuspending;
Debug.WriteLine("App: " + Environment.CurrentManagedThreadId);
MyClass test = new MyClass();
}
protected override async void OnLaunched(LaunchActivatedEventArgs e) {
Debug.WriteLine("OnLaunched: " + Environment.CurrentManagedThreadId);
MyClass test = new MyClass();
}
}
Run Code Online (Sandbox Code Playgroud)
这会创建:
应用程序:3
StartLoad:3
阅读:4
EndLoad:4
OnLaunched:3
StartLoad:3
阅读:5
EndLoad:3
您正在运行最终将启动应用程序消息循环的线程中的代码,但在那个时间点尚未执行此操作.该SynchronizationContext表示UI还没有被创建并设置为当前上下文.因此,该async方法没有上下文来捕获并在每个之后发送延续await; 改为使用默认上下文,将延续发送到线程池.
一旦SynchronizationContext已经设置好,您需要稍后运行代码.这就是为什么它在你打电话时起作用的原因OnLaunched; 在设置上下文后运行.
如果你看一下它的值SynchronizationContext.Current,你会发现它在你的第一种情况下是空的,并且在第二种情况下有一个值.这不是检查当前线程的ID,而是更好地指示continuation是否能够在UI线程中运行.