如何检测非等待任务的完成? [英] How should completion of non-awaited tasks be detected?

查看:35
本文介绍了如何检测非等待任务的完成?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在另一个问题中,我发布了此代码片段:

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);
        }

我明确不想在 MonitorAsyncawait - 此代码正在向多个客户端建立新连接.

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆