强制异步 - 等待IProgress <t> .Report()同步

时间:2015-12-02 19:24:23

标签: c# .net async-await

我正在使用基于任务的异步模式(TAP)执行一些长任务,使用IProgress<T>向主UI报告进度。 Progress.Report似乎仅在其前面有另一个等待任务时才起作用。 例如,如果我在内联循环中使用,则报告消息仅在任务结束时发布:

public async Task<bool> DoSomething(IProgress<string> progress)
{
    progress.Report("Start");  // works
    await SomeTask();

    progress.Report("Message 1"); // works ONLY at end

    for ()
    {
        progress.Report("Message x"); // works ONLY at end
        // do some tasks inline
    }

    return true;
}

是否有某种方法可以强制同步发布报告消息? 感谢。

1 个答案:

答案 0 :(得分:3)

  

Progress.Report似乎只在前面有另一个await任务时才有效。

这是有道理的。 Progress<T>抓取SynchronizationContext并在您调用Report方法后发布到其中。如果您的异步方法不是非同步并且主要是在UI线程上完成的CPU工作,那么您不会释放消息循环来处理更多事件,因此您只需要看到它在方法调用结束时更新。

这就是Progress<T>.Report的实施方式:

protected virtual void OnReport(T value)
{
        // If there's no handler, don't bother going through the [....] context.
        // Inside the callback, we'll need to check again, in case 
        // an event handler is removed between now and then.
        Action<T> handler = m_handler;
        EventHandler<T> changedEvent = ProgressChanged;
        if (handler != null || changedEvent != null)
        {
            // Post the processing to the [....] context.
            // (If T is a value type, it will get boxed here.)
            m_synchronizationContext.Post(m_invokeHandlers, value);
        }
}

为了保持响应,您可以将for循环卸载到线程池线程:

public async Task<bool> DoSomethingAsync(IProgress<string> progress)
{
    progress.Report("Start");  // works
    await SomeTask();
    progress.Report("Message 1");

    await Task.Run(() =>
    {
        progress.Report("Message x");
        // Do more CPU bound work
    }
    return true;
}