我需要为移动应用中的任务调用添加超时功能。我尝试使用Task.WhenAny完成此操作,如下所示。这将返回首先完成的任务。我的问题是,最初我从这个任务获得了返回值,如果任务没有超时,我仍然需要它。
prob_end[3]
响应只是首先完成的任务。我如何得到它的结果?
答案 0 :(得分:1)
但有一个问题,您的CancellationTokenSource
如何创建和初始化,以及何时在其上调用Cancel
?
如果您的方法GetRequestAsync
接受CancellationToken
,则效果最佳。如果可能,请始终选择,因为您可以创建一个CancellationTokenSource
,在设定的时间段后启动取消。会保存您对Task.WhenAny
的调用。
一般来说,有多种选择,一种如下所示:
// Set timeout of 1 second
CancellationTokenSource cts = new CancellationTokenSource();
cts.CancelAfter(TimeSpan.FromSeconds(1));
...
Task task = restService.GetRequestAsync(articleAdr, articleParams);
// Wait until timeout or request is done.
await Task.WhenAny(task, Task.Delay(TimeSpan.FromMilliseconds(-1), cts.Token));
// If the cancellation is not yet requested the request was done before the timeout was reached
if(!cts.IsCancellationRequested)
{
var response = await task;
}
另一种选择是:
Task requestTask = restService.GetRequestAsync(articleAdr, articleParams);
var firstCompletedTask = await Task.WhenAny(requestTask, Task.Delay(1000, cts.Token));
if(firstCompletedTask == requestTask)
{
cts.Cancel(); // optionally, will cancel the delay task since it is of no use any more.
var response = await requestTask;
}
可以根据需要多次等待完成的任务,并且它总会产生相同的结果。
答案 1 :(得分:1)
我可以想到这种情况有三种不同的可能性。
前两个可以在Peter Bons' answer中找到。
第三个是存储您的两个任务,然后在QtObject {
readonly property bool foobar: someExpression
onFoobarChanged: {
if (foobar) { ... }
}
}
完成后检查状态。
await Task.WhenAny()
答案 2 :(得分:1)
我想你可以看看@jamesmontemagno MVVM Helpers。有一个extesion可以帮助您为任务添加超时
在这里,您可以找到詹姆斯解释如何使用它的视频
The-Xamarin-Show-12-MVVM-Helpers
(接近26:38分)
答案 3 :(得分:0)
我需要为移动应用中的任务调用添加超时功能。我尝试使用Task.WhenAny完成此操作,如下所示。
首先,您应该知道,如果不将CancellationToken
传递给GetRequestAsync
,您实际上并未取消该请求。它将继续处理。
其次,我觉得你的代码比较奇怪,因为在当前状态下可能有两个超时:Task.Delay
可能完成,或者CancellationToken
可能会发出信号。其中一个(Task.Delay
)是正常任务完成,另一个(CancellationToken
)是真正的取消。
如果CancellationToken
您的超时,那么您可以使用WaitAsync
库中的Nito.AsyncEx.Tasks
方法:
Task task = restService.GetRequestAsync(articleAdr, articleParams);
await task.WaitAsync(cts.Token);
var result = await task;
如果CancellationToken
是用户请求的取消,并且Task.Delay
是您要申请的超时,那么我建议您将超时建模为另一种取消:< / p>
Task task = restService.GetRequestAsync(articleAdr, articleParams);
using (var timeoutCts = CancellationTokenSource.CreateLinkedTokenSource(cts.Token))
{
timeoutCts.CancelAfter(1000);
await task.WaitAsync(timeoutCts.Token);
}
var result = await task;
如果您不想使用Nito.AsyncEx.Tasks
,那么您最好的选择可能是这样的(假设Task.Delay
是暂停,CancellationToken
是用户取消请求):
Task task = restService.GetRequestAsync(articleAdr, articleParams);
var completed = await Task.WhenAny(task, Task.Delay(1000, cts.Token));
if (completed != task)
throw new OperationCanceledException();
var result = await task;