【问题标题】:Exception handling in Always-running tasks始终运行的任务中的异常处理
【发布时间】:2021-11-09 08:31:45
【问题描述】:

经过无数小时的测试、搜索和提问后,我仍然卡在“始终运行”的任务上,或者异步 io/并行编程中不存在这种情况?

目前我有一个程序可以轮询 webapi 服务 (soap) 以获取传感器的状态(基于 IOT)。

我们编程的层次结构只是扁平化,step1 然后 step2 然后 step3 等等。

现在的问题是,如果第 3 步失败并出现异常,第 4-6 步将不会被执行。

所以我想把每个任务分成相应的任务。 例如;第 1 步启动程序连接到 webapi,第 2 步获取内存中的传感器列表,第 3 步启动任务。

有 3 个主要任务:1 个任务用于获取传感器的状态,另一个任务是检查网络服务器是否在线,最后一个任务是询问服务器是否有旧传感器的新传感器被删除。

所以第 4 步到第 6 步是 3 个任务。 -> 这些任务将始终运行,因为只是轮询服务器,这发生在计时器滴答声中

每 1 秒第 4 步,每 10 秒第 5 步,每分钟第 6 步。

到目前为止一切顺利,我可能会调用 var task1 = Task.Run( () => somevoidtask);

问题:如果其中一项任务失败,需要重新启动,如何处理? 我正在测试并遇到autoresetevent。 我将如何处理异常(被记录)并重新启动该任务?

在我经常看到的微软文档上:

var task = Task.Run();
task.wait();
if(task.status == task.faulted)
{
  get exception
}

只是简单的伪。

我目前的测试项目有这个:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace taskTest
{
    public class Program
    {
        public static void Main(string[] args)
        {

            var source = new CancellationTokenSource(20000);
            var source2 = new CancellationTokenSource();
            var source3 = new CancellationTokenSource();

            var token1 = source.Token;
            var token2 = source2.Token;
            var token3 = source3.Token;

            Task1(token1);
            Task2(token2);
            Task3(token3);

            Console.ReadLine();

        }





        private static void Task1(CancellationToken token)
        {
            while (true)
            {
                if (token.IsCancellationRequested)
                {
                    Console.WriteLine("Cancellation is request for this task.");
                    return;
                }
                Task.Delay(1000);
            }
        }

        private static void Task2(CancellationToken token)
        {
            while (!token.IsCancellationRequested)
            {
                try
                {
                    throw new NullReferenceException();
                }
 

           catch (Exception ex)
            {
                
            }
        }
        Console.WriteLine("Task2 is cancelled");
    }

    private static void Task3(CancellationToken token)
    {
        Task.Run(async () =>
        {
            while (!token.IsCancellationRequested)
            {
                Console.WriteLine($"Task3: getting executed every 10 second");
                await Task.Delay(10000);
            }
            Console.WriteLine("Task3 is cancelled");
        });
    }
}

}

也许我认为并非所有代码都是好的最佳实践。

【问题讨论】:

    标签: c# .net-4.6


    【解决方案1】:

    异常可能很棘手,因为很难知道它们是否使程序处于不可恢复的状态。如果发生这种情况,最好的办法是让您的程序崩溃并依靠外部系统重新启动它。

    对于您有理由确定可以安全继续的异常,只需捕获它们、记录并继续。或者执行任何其他需要的恢复过程。

    我不喜欢你的任何例子。 Task1/2 将一直阻塞直到被取消,并且只有 task2 有任何类型的异常处理。

    对于重复发生的任务,我建议使用计时器,无论如何,使用 Task.Delay 之类的东西只是一个围绕计时器的异步包装器。如果您确定没有线程安全问题,请使用在后台线程上触发的线程。处理您认为可以在计时器的事件处理程序中安全捕获的所有异常,考虑在关闭应用程序之前添加unhandled exception handler 以记录任何其他异常。让您的应用程序成为服务是让 Windows 处理在应用程序失败时重新启动您的应用程序的一种不错的方式。

    【讨论】:

    • 是的,这只是一个简单的测试示例,想法可能是它抛出异常以重新启动该任务。
    • 你也说任务 1 将被阻止,谷歌说在任务 1 中使用 while(true) 而不是 while(!token.iscancelled) wait 是错误的,它阻止它而不是任务3?
    • @Technology Researcher Task1 与调用者在同一个线程上运行,而且它根本不是异步的,所以它只会循环直到被取消。 Task.Delay 没有等待,因此只会创建一个在一段时间后完成的任务。由于没有其他线程可以访问 cancelTokenSource,它将永远循环。 Task3 在单独的线程上运行循环,因此不会阻塞。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-06
    • 1970-01-01
    • 1970-01-01
    • 2015-07-03
    相关资源
    最近更新 更多