等待任务延迟如何加速UI刷新?

3

我有一个视图模型,它正在获取一行记录并在Windows手机UI上显示。 这个获取数据的视图模型方法使用了许多带有Await的Tasks。

看起来如下:

async Task GetData()
{

    var dataCollection = await GetSomeData();
    await DoThis();
    await DoThat();
}

在调用“DoThis”后,UI会刷新。 现在我发现,在其他任务完成之前,在代码中引入Task.Delay,UI会立即刷新。这就是我的原始目标,即在“GetSomeData”返回后立即刷新UI,然后再启动其他任务。
如下所示:
async Task GetData()
{
    var dataCollection = await GetSomeData();
    await Task.Delay(100);
    await DoThis();
    await DoThat();
}

根据我的理解,通过调用Task.Delay之后,UI线程有机会进行刷新。但是如果没有调用Task.Delay,在DoThis方法被调用时,在找到第一个可等待的方法以便可以返回并继续UI刷新之前,会有一些时间的延迟。

我的问题是:

  1. 我理解得对吗?
  2. 这样在生产环境中使用安全吗?

感谢您的提前回答,希望我表述清楚了。

以下是这些方法的详细信息,因为没有这些信息,不能清楚地了解程序运行的情况... :(

async Task<ObservableCollection<MyModel>> GetSomeData()
{
    return await Task.Run(() =>
    {
        using (var db = new MainModelDataContext())
        {
            List<MyModel> temp =
                db.Models.Where(Some condition)
                  .Take(30)
                  .ToList();
            var returnCollection = new ObservableCollection<MyModel>(temp);
            return returnCollection;
        }
}

ObservableCollection(可观察集合)绑定在 UI 页面的列表控件上。这个方法是由页面视图模型调用的。

async Task DoThis()
{
   // do some data processing and then post that to the Server 
   // this is the first awaitable method after the data processing

   await (an HttpClientHandler).PostAsync();
}

任务DoThat()的流程与DoThis()相同。数据处理也使用async-await任务包装,并且它们仅在一些类属性上工作。

希望我表达清楚了。再次感谢大家。


2
DoThis()DoThat()是做什么的?听起来它们是有效的同步代码,可能不应该在UI线程上运行... - Jon Skeet
可能是您在其中一个方法中执行了一些同步代码,而对Task.Delay的调用只是给UI线程一个运行的机会。 - Daniel Kelley
你需要发布 GetSomeDataDoThis 方法。我假设它们内部正在运行长时间的同步操作。 - Yuval Itzchakov
感谢 @JonSkeet,已在 OP 中添加了相关代码。 - PRE
1
除非您尝试在非异步方法中使用await,否则该代码将无法编译。您为什么要等待Task.Run的返回值呢?为什么不直接声明一个返回任务的非异步方法呢?这种包装没有帮助... - Jon Skeet
显示剩余4条评论
1个回答

8
当你调用Task.Delay时,你将控制权交还给UI消息循环100毫秒,UI消息循环有机会处理其队列中的更多消息。这就是你经历“刷新”效果的原因。如果你的GetSomeData方法是真正异步的,那么在它的操作期间,你的UI应该保持响应,并且当它完成时,它将继续执行下一个await
如果没有出现这种效果,那么就意味着你的方法并不是真正的异步,更有可能是以同步的方式运行一个昂贵的操作,从而阻塞了你的UI线程。
在将此投入生产之前,你必须查看为什么需要Task.Delay来刷新你的UI。

谢谢,这很有道理。GetSomeData只是在TAsk.Run包装器中从数据库中获取一些数据。由于某些外部限制,我没有并行linq API可供运行。因此,该方法几乎是同步的,因此需要Task.Delay。 - PRE
4
不,如果它实际上返回了任务,那么它是合适的异步操作。如果你在GetSomeData方法中使用Task.Result,那么会有问题。因为我们看不到除了GetData之外的其他方法,所以很难提供详细信息。 - Jon Skeet
1
Jon 当然是正确的,我们需要看到你的方法才能进一步检查发生了什么。如果你将其包装在 Task.Run 中,它仍然应该是响应式的。 - Yuval Itzchakov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接