【发布时间】:2013-03-13 21:33:33
【问题描述】:
我有一些 UI 代码,其中的方法如下所示:
private async Task UpdateStatusAsync()
{
//Do stuff on UI thread...
var result = await Task.Run(DoBunchOfStuffInBackground);
//Update UI based on result of background processing...
}
目标是让 UI 在任何影响其状态的属性更改时更新相对复杂的计算状态。这里有几个问题:
- 如果我只是从每个更新状态的地方直接调用此方法,最终更新的状态可能不正确。假设属性 A 发生变化,然后属性 B 发生变化。即使 B 在 A 之后调用 UpdateStatusAsync,有时回调代码(最终的 UI 更新)也会以相反的顺序发生。所以:(A->更新)->(B->更新)->(B更新)->(A更新)。这意味着最终的 UI 显示的是陈旧状态(反映 A,但不反映 B)。
- 如果我总是等待之前的 UpdateStatusAsync 先完成(我目前正在做的事情),我可能会多次执行昂贵的状态计算。理想情况下,我应该只需要为一系列更新进行“最后一次”计算。
我正在寻找的是一个完成以下任务的干净模式:
- 最终状态“陈旧”的时间不应超过一小段时间(即我不希望 UI 与底层状态不同步)
- 如果短时间内发生多个更新调用(常见用例),我希望避免重复工作,而是始终计算“最新”更新。
- 由于多个更新可能发生在非常接近(即毫秒内)的几种情况下,如果有其他更新请求进来,有一种方法可以避免在短时间内启动处理会很方便。
这似乎应该是一个相当普遍的问题,所以我想我会在这里问是否有人知道这样做的特别干净的方法。
【问题讨论】:
-
这不就是这么简单:
if (update received) { store info; reset 100ms timer }; if (timer expires) { do calculation };? -
@Scott,这样的事情可能会奏效,尽管它可能会变得非常陈旧(例如,我可以每 10 毫秒获得更新 1 秒,在这种情况下,它会在 UI 之前花费整整一秒status 开始更新。)我试图在避免冗余计算和保持 UI 最新之间找到平衡。
-
如果你想保持这个总体思路,只需增加一点复杂性:`if (update received && counter 太过时。
-
好吧,如果您使用事件(甚至是
INotifyPropertyChanged事件),您可以查看Reactive Extensions,它具有节流、事件流的组合等等。只是一个想法。
标签: c# .net task async-await