强制异步等待IProgress<;T>;.要同步的Report()

本文关键字:同步 Report gt IProgress 等待 lt 异步 | 更新日期: 2023-09-27 18:25:27

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

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;
}

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

强制异步等待IProgress<;T>;.要同步的Report()

进度报告似乎只有在前面有另一个等待任务的情况下才有效。

这是有道理的。Progress<T>捕获SynchronizationContext,并在调用Report方法后向其发布。如果你是async,那么方法并不是真正的异步,并且大部分CPU工作都在UI线程上完成,那么你就不会释放消息循环来处理更多的事件,因此你只会看到它在方法调用结束时更新。

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;
}