C# 等待Windows应用商店应用程序和Windows Phone应用程序后的不同线程。。。?

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

我正在将Windows Phone应用程序移植到Windows 8,但在异步/等待方面遇到问题。有一个类需要一段时间来加载其所有数据。为了不阻塞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...
      });
   }
} 
在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()将是执行此操作的最佳位置,因为它是执行的第一件事情之一。很明显,这不是一个好办法