Task.WhenAny with timeout等待超过超时值

时间:2018-01-24 05:37:40

标签: c# async-await

我有这段代码:

var client = new TcpClient();
HttpRequestInfo.AddTimestamp("Connecting");
await Task.WhenAny(client.ConnectAsync(serverAddress, serverPort),
                   Task.Delay(TimeSpan.FromMilliseconds(300)));
HttpRequestInfo.AddTimestamp("Connected");
if(client.Connected){ ... }

其中HttpRequestInfo.AddTimestamp只是使用Stopwatch类记录命名的时间戳。

在日志中,我有时会看到:

"Connecting":110ms - "Connected":747ms
"Connecting":35ms - "Connected":3120ms
"Connecting":38ms - "Connected":3053ms

我认为这种方法可以让我有机会通过超时(300ms)限制连接。但是,我发现这行代码有时(非常罕见)运行时间超过300毫秒。 这种行为的原因是什么?

1 个答案:

答案 0 :(得分:3)

docs州:

  

此方法取决于系统时钟。这意味着时间   延迟将近似等于系统时钟的分辨率   延迟参数小于系统时钟的分辨率,   在Windows系统上约为15毫秒。

因此,它可以解释超过300毫秒大约15毫秒的超时超时,因为延迟必须根据系统时钟分辨率进行调整。

它不能解释您更长时间的更长时间 我假设由于某种原因,ConnectAsync可能会在返回调用方法之前阻塞一段时间,如果它是真的,则在第一次登录和实际触发Task.Delay之间需要一段时间并且问题不是与延迟有关。

您可以尝试使用此代码并监控日志,可能会在启动ConnectAsync时隐藏丢失的时间:

var client = new TcpClient();
HttpRequestInfo.AddTimestamp("Launching ConnectAsync");
var connectAsyncTask = client.ConnectAsync(serverAddress, serverPort);
HttpRequestInfo.AddTimestamp("ConnectAsync launched");
HttpRequestInfo.AddTimestamp("Launching Delay");
var delayTask= Task.Delay(TimeSpan.FromMilliseconds(300));
HttpRequestInfo.AddTimestamp("Delay launched");
var firstTask = await Task.WhenAny(connectAsyncTask, delayTask);
if(firstTask == connectAsyncTask)
{ 
    HttpRequestInfo.AddTimestamp("Connected");
}
else
{
    HttpRequestInfo.AddTimestamp("Timeout");
}