是否有一种方法等待任务结束但在一定时间后继续前进,但让任务本身继续进行?我希望在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;
}
}
答案 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。