C# 正在等待超时的任务
我正在尝试编写一个助手方法,它允许我传入任意任务和超时。如果任务在超时之前完成,则调用成功委托,否则调用错误委托。方法如下所示:C# 正在等待超时的任务,c#,.net,async-await,task,C#,.net,Async Await,Task,我正在尝试编写一个助手方法,它允许我传入任意任务和超时。如果任务在超时之前完成,则调用成功委托,否则调用错误委托。方法如下所示: public static async Task AwaitWithTimeout(Task task, int timeout, Action success, Action error) { if (await Task.WhenAny(task, Task.Delay(timeout)) == task) {
public static async Task AwaitWithTimeout(Task task, int timeout, Action success, Action error)
{
if (await Task.WhenAny(task, Task.Delay(timeout)) == task)
{
if (success != null)
{
success();
}
}
else
{
if (error != null)
{
error();
}
}
}
现在这似乎在大多数情况下都有效,但我也想编写一些测试来确保。出乎意料的是,该测试失败了,并调用了错误委托而不是成功委托:
var taskToAwait = Task.Delay(1);
var successCalled = false;
await TaskHelper.AwaitWithTimeout(taskToAwait, 10, () => successCalled = true, null);
Assert.IsTrue(successCalled);
但是,此测试为绿色:
var taskToAwait = Task.Run(async () =>
{
await Task.Delay(1);
});
var successCalled = false;
await TaskHelper.AwaitWithTimeout(taskToAwait, 10, () => successCalled = true, null);
Assert.IsTrue(successCalled);
如何使两个测试都是绿色的?我对Task.When的使用是否不正确?计时器不准确。默认情况下,它们的准确度约为15毫秒。任何低于该值的值都将在15毫秒的间隔内触发 假设你有1ms定时器和10ms定时器;两者大致相等,因此得到的结果不一致 您在
Task.Run
中包装并声称正在工作的代码只是巧合。我试了几次,结果都不一致。它有时会因为上述相同的原因而失败
您最好增加超时时间,或者只是传递一个已经完成的任务
例如,以下测试应始终通过。记住,你的测试应该是一致的,而不是脆弱的
[Test]
public async Task AwaitWithTimeout_Calls_SuccessDelegate_On_Success()
{
var taskToAwait = Task.FromResult(0);
var successCalled = false;
await TaskHelper.AwaitWithTimeout(taskToAwait, 10, () => successCalled = true, ()=>{ });
Assert.IsTrue(successCalled);
}
对于永不结束的任务,请使用TaskCompletionSource
,不要设置其结果
[Test]
public async Task AwaitWithTimeout_Calls_ErrorDelegate_On_NeverEndingTask()
{
var taskToAwait = new TaskCompletionSource<object>().Task;
var errorCalled = false;
await TaskHelper.AwaitWithTimeout(taskToAwait, 10, () => { }, ()=> errorCalled = true);
Assert.IsTrue(errorCalled);
}
请注意,上述方法是一种扩展方法;因此,您可以使用任务实例调用它
await taskToAwait.AwaitWithTimeout(10, () => { }, ()=> errorCalled = true);//No nulls, just empty delegate
Delay(1)
非常短(特别是在调试时)-在单独的线程上启动它可以使它足够长,使您的测试大部分时间都能通过。尝试使用更长的延迟或更好的任务,允许在测试中手动同步完成。谢谢。对于如何测试错误场景,您有什么建议吗?也就是说,输入一个从未完成的任务。现在,我仍然使用Task.Delay()来完成这个任务(只是将延迟设置得很高,超时设置得有点低)@user1202032当然。更新了我的答案,以解决永无止境的任务。虽然核心概念(使用task.WhenAny
等待两个任务)是正确的,但它周围的API感觉脏兮兮的<代码>行动如果你需要从中连接另一个任务
,那么成功就是一团糟-你最终会得到丑陋的捕获。我只需在超时场景中抛出一个TimeoutException
,并将成功完成视为成功完成。在性能关键的情况下,任务
返回类型也可以工作(其中true
表示成功完成,false
表示超时)。然后还有超时任务最终完成的处理(此处讨论:)。当然,别忘了ConfigureAwait(false)
——绝对没有理由不在helper或library方法中使用它。@KirillShlenskiy是的,这正是我的想法<代码>任务比学员更有意义。更好的时间例外。我把它留给OP。
await taskToAwait.AwaitWithTimeout(10, () => { }, ()=> errorCalled = true);//No nulls, just empty delegate