C# 等待Windows应用商店应用程序和Windows Phone应用程序后的不同线程。。。?
我正在将Windows Phone应用程序移植到Windows 8,但在异步/等待方面遇到问题。有一个类需要一段时间来加载其所有数据。为了不阻塞UI线程,加载在单独的任务/线程中完成。加载完成后,需要更新UI线程:C# 等待Windows应用商店应用程序和Windows Phone应用程序后的不同线程。。。?,c#,windows-phone-8,windows-store-apps,async-await,C#,Windows Phone 8,Windows Store Apps,Async Await,我正在将Windows Phone应用程序移植到Windows 8,但在异步/等待方面遇到问题。有一个类需要一段时间来加载其所有数据。为了不阻塞UI线程,加载在单独的任务/线程中完成。加载完成后,需要更新UI线程: public class MyClass { public MyClass() { ... LoadData(); ... } private async void LoadData() { Debug.WriteL
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...
});
}
}
在Windows Phone上,输出如下所示:
惊人负荷:1
阅读:4
端载:1
当我在Windows应用商店应用程序中执行相同的代码时,输出为:
惊人负荷:1
阅读:4
端载:4
在Windows Phone上,等待前后的ThreadId相同在Windows 8上,等待后的ThreadId不同于等待前的ThreadId。这里的线程与后台任务中的线程相同。由于此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();
}
}
这就产生了:
应用程序:3
惊人负荷:3
阅读:4
端载:4
OnLaunched:3
惊人负荷:3
阅读:5
端载:3
最有可能的原因是,
LoadData
实际上没有在UI线程上被调用。最有可能的原因是,LoadData
实际上没有在UI线程上被调用。您正在从最终将启动应用程序消息循环的线程运行代码,但当时它还没有这样做。表示UI的SynchronizationContext
尚未创建并设置为当前上下文。因此,async
方法在每次wait
之后都没有上下文来捕获和发送延续;改为使用默认上下文,将continuations发送到线程池
一旦设置了SynchronizationContext
,您需要稍后运行代码。这就是为什么从OnLaunched
调用它时它会工作的原因;在设置上下文后运行的
如果查看SynchronizationContext.Current的值,您会发现第一种情况下它为null,第二种情况下它有一个值。这比检查当前线程的ID要好得多,可以更好地指示continuations是否能够在UI线程中运行。您是从最终将启动应用程序消息循环的线程运行代码的,但当时它还没有这样做。表示UI的
SynchronizationContext
尚未创建并设置为当前上下文。因此,async
方法在每次wait
之后都没有上下文来捕获和发送延续;改为使用默认上下文,将continuations发送到线程池
一旦设置了SynchronizationContext
,您需要稍后运行代码。这就是为什么从OnLaunched
调用它时它会工作的原因;在设置上下文后运行的
如果查看SynchronizationContext.Current的值,您会发现第一种情况下它为null,第二种情况下它有一个值。这比检查当前线程的ID要好得多,可以更好地指示continuations是否能够在UI线程中运行。您是否尝试过
await ReadDataAsync()。ConfigureAwait(true)
谢谢,但结果完全相同。如果不是await
ing任何东西,则无需使您的OnLaunched
方法async
,您是否尝试了await ReadDataAsync()。ConfigureAwait(true)代码>谢谢,但是结果是完全一样的。如果你的方法不是等待
任何东西,就不需要让你的OnLaunched
方法异步
,MyClass的构造函数(以及LoadData()的构造函数)是从App类中的App()方法调用的。这应该是UI线程,不是吗?@AndreiHerford即使它来自将用于运行messageloop的线程,如果message loop尚未启动,那么将不会有一个SynchronizationContext
表示要捕获的async
方法的UI上下文。MyClass的构造函数(因此加载数据()也可以从App类中的App()方法调用。这应该是UI线程,不是吗?@AndreiHerford即使它来自将用于运行messageloop的线程,如果消息循环尚未启动,那么将不会有一个SynchronizationContext
来表示async
方法要捕获的UI上下文。非常感谢您的精彩解释!还有一个问题:MyClass必须尽快初始化,因为它可以从应用程序的所有地方访问。我认为App()将是执行此操作的最佳位置,因为它是执行的第一件事情之一。显然这不是一个好主意。OnLaunched是这方面的最佳场所,还是有其他方法可以更早地执行并正确设置所有内容?@AndreiHerford不是winphone开发人员,我真的不能说。非常感谢您的精彩解释!还有一个问题:MyClass必须尽快初始化,因为它可以从应用程序的所有地方访问。我认为App()将是执行此操作的最佳位置,因为它是执行的第一件事情之一。很明显,这不是一个好办法