.net 等待异步操作时更新进度条

b1zrtrql  于 2023-02-26  发布在  .NET
关注(0)|答案(3)|浏览(146)

我试图在等待异步IO操作时更新进度条。下面的代码就是这么做的。

Task<string> io = SomeOperationAsync();

while(!io.IsComplete)
{
    progressBar.Value = value // add some progress;
    await Task.Delay(TimeSpan.FromMilliseconds(200));
}    

string result = await io;

这很好用。进度条填充得很顺利。
但是正如您所看到的,我将每200毫秒检查一次完成情况,而不是真正地等待它,我可能最终会等待长达200毫秒的时间太长。
是否有更好的方法来实现这一点,以便我的方法可以在IO操作完成后立即返回?

qxgroojn

qxgroojn1#

如果可以的话,让SomeOperationAsync直接使用标准进度报告模式报告进度,那么在等待呼叫时报告进度就超级简单了:

var progress = new Progress<TValue>(value => progressBar.Value = value);
string result = await SomeOperationAsync(progress);
yzxexxkh

yzxexxkh2#

您可以使用. WhenAny()返回任何任务完成的时间。如果主任务在延迟之前完成,则会返回代码的小重构。

Task<string> io = SomeOperationAsync();

while(!io.IsComplete)
{
    progressBar.Value = value // add some progress;
    await Task.WhenAny(io, Task.Delay(TimeSpan.FromMilliseconds(200)));
}    

string result = await io;
pvabu6sv

pvabu6sv3#

Daniel's解决方案是最实用的一种,但您可能还想知道最高效的解决方案:

Task<string> io = SomeOperationAsync();

using PeriodicTimer timer = new(TimeSpan.FromMilliseconds(200));

_ = io.ContinueWith(_ => timer.Dispose(), CancellationToken.None,
    TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);

while (true)
{
    await timer.WaitForNextTickAsync();
    if (io.IsCompleted) break;
    progressBar.Value = value // add some progress;
}    

string result = await io;

PeriodicTimer将持续每200毫秒滴答一次,直到它被处理,在这种情况下,WaitForNextTickAsync将立即完成,结果为false
一般来说,我会避免像上面的ContinueWith这样的“发射后忘记”任务,但在这种情况下,相关的风险可以忽略不计。最坏的情况是,循环将晚200毫秒完成。只要在循环内部检查io.IsCompleted,就没有无限循环的风险。

相关问题