【问题标题】:strict MVVM and Task.ConfigureAwait(false)严格的 MVVM 和 Task.ConfigureAwait(false)
【发布时间】:2014-12-01 21:07:59
【问题描述】:

我正在重写 MVVM 框架的某些部分以利用 async/await 功能,请考虑以下 VM 代码:

private async Task LoadDossier(int ID)
    {
        //VM INotifyProperty
        Dossiers = new ObservableCollection<Dossier>(await BubManager.GetAllBubDossiersForEmployeeByDossierIdAsync(ID).ConfigureAwait(false));
        //VM INotifyProperty
        SelectedDossier = Dossiers.First(x => x.Id == ID);
        //VM INotifyProperty
        DossierEmployer = await EmployerManager.GetEmployerByIdAsync(SelectedDossier.EmployerId).ConfigureAwait(false);
        //VM INotifyProperty
        DossierEmployee = await EmployeeManager.GetEmployeeByIdAsync(SelectedDossier.EmployeeId).ConfigureAwait(false);
        //All VM INotifyProperties
        if (SelectedDossier != null && DossierEmployer != null)
        {
            RszNr = DossierEmployer.RszNr;
            FundsNr = DossierEmployer.FundsNr;
            RrNr = DossierEmployee.RrNr;
        }
        RefreshGlobalCommanding();
    }

由于我使用的是严格的 MVVM,因此这里没有一个属性需要 UI 线程,因此我在任何地方都使用ConfigureAwait(false)。我知道从ObservableCollection 添加/删除时这是不可能的,但这里不是这种情况。

  • 此代码是一种好的做法吗?
  • 如果是,那么为什么不能将其设为默认行为?不断输入ConfigureAwait(false) 无助于IMO 的可读性

编辑

在与斯蒂芬讨论之后,我得出的结论是,基本上是一样的。

  • 如果您使用ConfigureAwait(false),您是在告诉 WPF 回调不必在 UI 线程上。设置 INotifyProperty 时,WPF 会确保 UI 线程收到通知。
  • 如果您不这样做,WPF 确保回调在 UI 线程上并且完全没有问题。

这两种情况都使 WPF 在某些时候执行 UI 线程编组。但是,我比较了两者的性能,并且存在显着差异。我执行了 1000 次循环,其中一个对象被绑定到一个视图,然后再次设置为 null,以下是以毫秒为单位的结果:

一个等待调用,任务延迟为 10 毫秒

  • 15623ms 与ConfigureAwait(false)
  • 51700ms 没有

三个等待调用,任务延迟为 10 毫秒

  • 46917ms 与ConfigureAwait(false)
  • 82647ms 没有

这个基准测试远非完美,但似乎将属性编组回 UI 线程比在 await 调用后强制所有内容在同一线程上运行成本更低。然而,这需要更多的测试才能为所有场景给出明确的答案。

我只是将其放在这里以证明两者之间存在差异。我的建议是不要在这种情况下使用 ConfigureAwait,因为它会在更改代码时增加发生异常的机会,可读性较差,并且同事可能不理解这一点并通过使用它来获得错误的安全感。

【问题讨论】:

  • 等等,这里没有一个属性需要 UI 线程。你不绑定ViewDossiers?如果你这样做了,那么你的假设是错误的。
  • 正如斯蒂芬所说,WPF 处理简单属性的 UI 线程封送处理

标签: c# wpf mvvm async-await


【解决方案1】:

这段代码是个好习惯吗?

就个人而言,我选择将所有数据绑定属性视为具有 UI 关联性。

一个原因是不同的 MVVM 框架在这方面有不同的能力;确实,WPF 会为您处理这个问题(对于简单的属性),但其他人不会。

如果是,那为什么不能将其设为默认行为?

async 在 CTP 中时,有很多关于 await 的默认行为的讨论。各有利弊。

【讨论】:

  • 什么是简单属性,然后它们变得不那么简单了?我在尝试绑定到属性时遇到了一些错误,这些错误在另一个线程中进行了更改,这就是我很好奇的原因。
  • 感谢斯蒂芬的忍者回答(以及您在此主题上发表的所有优秀博文)。但是,如果我理解正确,这个特定场景是有效代码,并且比不使用 ConfigureAwait 的性能略好,对吗?
  • @ArneDeruwe:我不希望有更好的表现。正在发生的一切是 WPF 正在编组到 UI 线程 for 你,我更喜欢自己做。
  • 好的有道理,根据内部绑定实现,它可能会为每个属性编组它,可能由于多个属性而性能较低?有趣的测试场景:)
  • @Sinatr 从 3.5.1 (IIRC) 开始,如果您从任何非 UI 线程引发 PropertyChanged 事件,WPF 的 Binding 类将不会引发任何异常。 DependencyProperties 尚未更改为以这种方式运行,因此您必须在触摸它们之前编组到 UI 上。所以如果你实现了 INPC,你就不用担心线程亲和性了。
猜你喜欢
  • 2015-04-09
  • 2020-03-24
  • 1970-01-01
  • 2014-02-15
  • 1970-01-01
  • 2011-03-09
  • 2016-03-23
  • 2016-06-22
  • 2016-06-04
相关资源
最近更新 更多