如何检测非等待任务的完成? [英] How should completion of non-awaited tasks be detected?
问题描述
在另一个问题中,我发布了此代码片段:
In a different question I posted this code snippet:
tcpListener = new TcpListener(IPAddress.Any, port);
tcpListener.Start();
while (!cancellation.IsCancellationRequested)
{
var client = await tcpListener.AcceptTcpClientAsync();
//Monitor services TCP messages to this client
var monitor = new My.Monitor(client);
_ = monitor.MonitorAsync(cancellation.Token);
}
我明确不想在 MonitorAsync
上 await
- 此代码正在向多个客户端建立新连接.
I excplicitly do not want to await
on MonitorAsync
- this code is spooling up new connections to multiple clients.
这会导致孤立"任务 - 如果 MonitorAsync
抛出,我们将不会注意到或无法响应.我们根本不知道它已经完成.
This leads to 'ophaned' tasks - if MonitorAsync
throws, we are not going to notice or be able to respond. We don't know it has completed at all.
Monitor
实例将在客户端会话开始和结束时不断创建和处理.它们可能会存储在一个集合中:
Monitor
instances are going to be continually created and disposed as client sessions start and end. Likely they would be stored in a collection:
tcpListener = new TcpListener(IPAddress.Any, port);
tcpListener.Start();
while (!cancellation.IsCancellationRequested)
{
var client = await tcpListener.AcceptTcpClientAsync();
//Monitor services TCP messages to this client
var monitor = new Monitor(client);
monitorTasks.Add(monitor.MonitorAsync(cancellation.Token));
}
但是由于集合会经常添加和删除元素,我很确定 Task.WhenAny(monitorTasks)
不合适?
But since the collection will have elements added and removed often, I am pretty sure Task.WhenAny(monitorTasks)
is not suitable?
我可以考虑的唯一其他想法是使用 ContinueWith
例如:
The only other idea I can consider is using ContinueWith
e.g.:
tcpListener = new TcpListener(IPAddress.Any, port);
tcpListener.Start();
while (!cancellation.IsCancellationRequested)
{
var client = await tcpListener.AcceptTcpClientAsync();
//Monitor services TCP messages to this client
var monitor = new Monitor(client);
_ = monitor.MonitorAsync(cancellation.Token).ContinueWith(() => MonitoringFinished(monitor));
}
这些是一个很好的解决方案还是 TPL 提供了更好的解决方案?拥有火而忘记"的情况一定是相当普遍的.任务并行但仍会跟踪失败.
Is either of these a good solution or does TPL provide something nicer? It must be fairly common to have "fire and forget" task parallelism but still track failures.
推荐答案
OP 还没有提到其他几个选项:Task.Run
, TaskScheduler.UnobservedTaskException
, RaiseError 扩展
.等
There are several other options that haven't been mentioned by the OP: Task.Run
, TaskScheduler.UnobservedTaskException
, RaiseError extension
. etc.
Task.Run(() =>
{
//Your fire and forget action call
}).ContinueWith((task) =>
{
if (task.IsFaulted) throw task.Exception; //not the best because of rethrow
//if (task.IsCompleted) { // do some extra stuff if needed };
});
显然可以使用TaskContinuationOptions.OnlyOnFaulted
进一步优化.
Obviously it can be further optimized with the use of TaskContinuationOptions.OnlyOnFaulted
.
启用该功能
<runtime>
<ThrowUnobservedTaskExceptions enabled="true"/>
</runtime>
订阅
TaskScheduler.UnobservedTaskException += (s, e) => {
e.SetObserved();
throw e.Exception;
};
这种方法的问题是只有在任务完成时才会触发此事件.在您的情况下,这可能是也可能不是问题
The problem with this approach that this event is only fired when the Task is finalized. Which may or may not be a problem in your case
它只是 continueWith 的替代
It is just an alternative to the continueWith
public static void RaiseError(this Task task)
{
if (task.IsFaulted)
{
_ = RaiseError(task);
}
async static Task RaiseError(Task task)
{
try
{
await task.ConfigureAwait(false);
// do some extra stuff if needed
}
catch
{
throw;
}
}
}
这篇关于如何检测非等待任务的完成?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!