通知正在进行长时间的异步任务-正确的方法

时间:2018-11-05 13:11:09

标签: c# asynchronous async-await progress

我有一个控制台程序,该程序将异步HTTP请求发送到外部Web API。 (Console.WriteLine("I ain't dead - yet")
这些任务可能需要几分钟才能完成-在此期间,我希望向用户显示该应用程序仍在运行-例如,每10秒发送一次 try { var task = httpClient.GetAsync(uri); //actually this is an SDK method call (which I cannot control and which does not report progress itself) while (!task.IsCompleted) { await Task.Delay(1000 * 10); this.Logger.Log(Verbosity.Verbose, "Waiting for reply..."); } onSuccessCallback(task.Result); } catch (Exception ex) { if (onErrorCallback == null) { throw this.Logger.Error(this.GetProperException(ex, caller)); } this.Logger.Log(Verbosity.Error, $"An error when executing command [{action?.Command}] on {typeof(T).Name}", ex); onErrorCallback(this.GetProperException(ex, caller)); }

我不确定如何正确地做,没有隐藏异常,引入死锁等的风险。

我知道IProgress ,但是我不知道在这种情况下是否可以引入它。我正在等待一个不报告进度的异步调用。 (本质上是一个调用httpClient GetAsync()方法的SDK

也: 我无法将GUI设置为“ InProgress”,因为没有GUI,它是一个控制台应用程序-如果我不时不发送更新消息,对于用户来说好像停止工作了。

当前想法:

.foto {
  width:200px;
  height:200px;
  background-size:contain;
}

3 个答案:

答案 0 :(得分:4)

让我为您整理一下这段代码

async Task Main()
{
    var reporter = new ConsoleProgress();
    var result = await WeatherWaxProgressWrapper(() => GetAsync("foo"), reporter);

    Console.WriteLine(result);
}



public async Task<int> GetAsync(string uri)
{
    await Task.Delay(TimeSpan.FromSeconds(10));
    return 1;
}

public async Task<T> WeatherWaxProgressWrapper<T>(Func<Task<T>> method, System.IProgress<string> progress)
{
    var task = method();
    while(!task.IsCompleted && !task.IsCanceled && !task.IsFaulted)
    {
        await Task.WhenAny(task, Task.Delay(1000));
        progress.Report("I ain't dead");
    }
    return await task;
}

public class ConsoleProgress : System.IProgress<string>
{
    public void Report(string value)
    {
        Console.WriteLine(value);
    }
}

答案 1 :(得分:0)

您可能拥有一个永无止境的Task作为信标,该信标每10秒发出一次信号,并在长时间运行的I / O操作完成后将其取消:

var beaconCts = new CancellationTokenSource();
var beaconTask = Task.Run(async () =>
{
    while (true)
    {
        await Task.Delay(TimeSpan.FromSeconds(10), beaconCts.Token);
        Console.WriteLine("Still going...");
    }
});
await LongRunningOperationAsync();
beaconCts.Cancel();

答案 2 :(得分:-1)

您正在寻找System.Progress<T>,这是IProgress的绝佳实现。

https://docs.microsoft.com/en-us/dotnet/api/system.progress-1

您可以在“ UI线程”或主线程上创建此类的对象,并为您捕获SynchronizationContext。将其传递给您的工作线程,对Report的每次调用都将在捕获的线程上执行,您不必担心任何事情。

在WPF或WinForms应用程序中非常有用。