等待任务,但在一定时间后忘记

时间:2019-06-11 14:25:07

标签: c# asp.net-core task wait

是否有一种方法等待任务结束但在一定时间后继续前进,但让任务本身继续进行?我希望在5秒内从任务中得到回应,并且不想等待更长的时间-但是,如果经过了5秒以上,我只想继续前进,而不是实际上取消任务(排除取消)令牌)。

我正在使用.NET Core / C#。

private async Task<string> MakeAuthRequest(Request request)
{
    try
    {
        var response = await SometimesLongMethod(request); // something needs to be done here, just not sure what
        return response.Message;
    }
    catch(Exception e)
    {
        logger.Error(e, "Error occurred");
        return string.Empty;
    }
}

3 个答案:

答案 0 :(得分:0)

您可以使用Task.Delay来代表一个时间跨度的任务,然后使用Task.WhenAny来确定哪个任务首先完成:

private async Task<string> MakeAuthRequest(Request request)
{
  try
  {
    var timer = Task.Delay(TimeSpan.FromSeconds(5));
    var authTask = SometimesLongMethod(request);
    var completedTask = await Task.WhenAny(timer, authTask);
    if (completedTask == authTask)
      return await authTask;
    return string.Empty; // Did not complete in 5 seconds.
  }
  catch(Exception e)
  {
    logger.Error(e, "Error occurred");
    return string.Empty;
  }
}

答案 1 :(得分:0)

类似的事情会发生-如果您的方法快速返回,请记住取消延迟任务!

 public static async Task<T> OnlyWaitFor<T>(Task<T> theTask, TimeSpan waitTime)
 {
    var cts = new CancellationTokenSource();
    var delayTask = Task.Delay(waitTime,cts.Token);
    var result = await Task.WhenAny(delayTask, theTask);
    if (result == delayTask)
        return default(T);
    cts.Cancel();
    return await theTask;

}

测试代码:

 public static async Task<string> ShortTask()
 {
     await Task.Delay(500);
     return "ShortFoo";
 }

 public static async Task<string> LongTask()
 {
     await Task.Delay(5000);
     return "LongFoo";
 }

var sw = new Stopwatch();
sw.Start();
var result1 = await OnlyWaitFor(ShortTask(), TimeSpan.FromSeconds(1));
sw.Stop();
Console.WriteLine($"Got back '{result1}' in {sw.ElapsedMilliseconds}ms");

sw.Reset();
sw.Start();
var result2 = await OnlyWaitFor(LongTask(), TimeSpan.FromSeconds(1));
sw.Stop();
Console.WriteLine($"Got back '{result2}' in {sw.ElapsedMilliseconds}ms");

输出:

Got back 'ShortFoo' in 524ms
Got back '' in 1006ms

答案 2 :(得分:-1)

下面的扩展方法允许将超时设置为等待任何任务。任务本身将继续运行。 Task<T>超时的结果将是默认值T。例如,超时Task<int>的值为0。

public static Task WithTimeout(this Task task, int timeout)
{
    var delayTask = Task.Delay(timeout);
    return Task.WhenAny(task, delayTask).Unwrap();
}

public static Task<T> WithTimeout<T>(this Task<T> task, int timeout)
{
    var delayTask = Task.Delay(timeout).ContinueWith(_ => default(T),
        TaskContinuationOptions.ExecuteSynchronously);
    return Task.WhenAny(task, delayTask).Unwrap();
}

可以在this answer中找到用法示例。

如果T的默认值是有效的返回值,则您可能更愿意处理异常:

public static Task<T> WithTimeoutException<T>(this Task<T> task, int timeout)
{
    var delayTask = Task.Delay(timeout).ContinueWith<T>(_ => throw new TimeoutException(),
        TaskContinuationOptions.ExecuteSynchronously);
    return Task.WhenAny(task, delayTask).Unwrap();
}

更新:如果您改变主意并希望取消超时任务,请参阅以下问题:Task.WhenAny with cancellation of the non completed tasks and timeout