任务.WhenAny超时等待时间比超时值更长

4

I have this block of code:

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

我原以为这种方法可以让我通过超时(300毫秒)来限制连接。然而,我发现这行代码有时(很少)运行时间超过了300毫秒。这种行为的原因是什么?

1个回答

3

根据文档所述:

此方法依赖于系统时钟。这意味着,如果延迟参数小于系统时钟的分辨率,即约为 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");
}

在这种情况下,据我理解,延迟可能约为285-315毫秒。但在我的情况下,该方法执行大约3015毫秒(例如3053-38)。 - Oleg Varlamov
谢谢!我会尝试以这种方式创建时间戳。然而,我觉得结果并没有改变。 - Oleg Varlamov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接