我有以下代码:
我在这里不能使用
连接必须分别处理 - 我不希望处理一个连接时出现任何错误影响其他连接的情况。
这里所述的“fire and forget”解决方案可行,但通常规则是始终
看起来我打破了规则,所以在这种情况下有更好、更可靠的方法来同时处理变量(任务数量随时间变化)数量的异步I/O绑定任务吗?
更多信息:
- 每次调用
while (!cancellationToken.IsCancellationRequested)
{
var connection = await listener.AcceptAsync(cancellationToken);
HandleConnectionAsync(connection, cancellationToken)
.FireAndForget(HandleException);
}
FireAndForget
是一个扩展方法:
public static async void FireAndForget(this ValueTask task, Action<Exception> exceptionHandler)
{
try
{
await task.ConfigureAwait(false);
}
catch (Exception e)
{
exceptionHandler.Invoke(e);
}
}
while loop
是服务器生命周期。当新的连接被接受后,它会启动一些“后台任务”,以便处理这个新连接,然后while loop
返回到接受新连接的状态而不需要等待任何东西 - 暂停生命周期。我在这里不能使用
await
HandleConnectionAsync
(暂停生命周期),因为我想立即接受另一个连接(如果有的话)并能够同时处理多个连接。HandleConnectionAsync
是I/O绑定的,并且一次只处理一个连接,直到关闭(任务完成后的某个时间)。连接必须分别处理 - 我不希望处理一个连接时出现任何错误影响其他连接的情况。
这里所述的“fire and forget”解决方案可行,但通常规则是始终
await
异步方法,永远不要使用async void
。看起来我打破了规则,所以在这种情况下有更好、更可靠的方法来同时处理变量(任务数量随时间变化)数量的异步I/O绑定任务吗?
更多信息:
- 每次调用
AcceptAsync
都会分配系统资源,甚至在返回连接之前,我希望尽可能避免这种情况(连接可能不会被返回几个小时(代码可能会“等待”几个小时)- 直到某个外部客户端决定连接到我的服务器)。最好假设这是我不希望同时/并行调用的方法 - 一次只有一个AcceptAsync
足够了。
- 请考虑到我每天可以有数百万个客户端连接和断开到我的服务器,服务器(while loop
)可以工作很多天。
- 我不知道在特定时间需要处理多少个连接。
- 我知道我的程序能够同时处理的最大连接数。
- 如果达到了maximum number of connections
限制,则AcceptAsync
不会返回新连接,直到其他活动连接关闭,因此我不需要担心这个问题,但任何基于该限制的解决方案都必须考虑到活动连接可能关闭并且仍然需要处理新连接 - 连接数量随时间变化。 "fire and forget"对此没有问题。
- 关于HandleConnectionAsync
的代码不相关-它只处理一个连接,直到关闭(任务完成后的某个时间),并且是I/O绑定的(HandleConnectionAsync
一次只处理一个连接,但是我们当然可以启动多个HandleConnectionAsync
任务来同时处理多个连接 - 这就是我用“fire and forget”做的)。
Task.WaitAll
? - NotFoundTask.WhenAll
- 我不确定如何在这里应用它,因为我没有固定的任务集合。正如我在“更多信息”部分中提到的那样,我不知道特定时间的连接数量 - 它可以是一个、两个或1000个,并且可能会随时间变化。 - user6440521Task.WhenAll
来捆绑它们,但最终如果你不想“发射并忘记”,你必须在某个时刻等待它们完成。无论是使用捆绑任务还是Task.WaitAll
。 - NotFound