【问题标题】:Where to handle exceptions thrown by Task在哪里处理 Task 抛出的异常
【发布时间】:2014-05-15 19:40:55
【问题描述】:

我正在单独的任务中执行一些轮询 IO 循环。这些循环可能会遇到异常。如果遇到异常,我想提醒调用者以便它可以:

  1. 记录下来
  2. 杀死所有IO线程
  3. 重置连接
  4. 重启 IO 线程

用户界面必须保持响应。处理这种情况的首选方法是什么?我在下面包含了一个说明性程序。

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

namespace TaskExceptionCatching
{
    class Program
    {
        static void Main(string[] args)
        {
            startLoops();

            System.Console.WriteLine("Type 'Exit' when you're ready to stop.");
            while (System.Console.ReadLine() != "Exit")
            {
                System.Console.WriteLine("Seriously, just type 'Exit' when you're ready to stop.");
            }
        }

        static private void startLoops()
        {
            System.Console.WriteLine("Starting fizzLoop.");
            var fizzTask = Task.Factory.StartNew(new Action(fizzLoop));

            System.Console.WriteLine("Starting buzzLoop.");
            var buzzTask = Task.Factory.StartNew(new Action(buzzLoop));
        }

        static private void fizzLoop()
        {
            while (true)
            {
                //simulate something error prone, like some risky IO
                System.Threading.Thread.Sleep(200);
                bool isErr = (new Random().Next(1, 100) == 10);
                if (isErr)
                    throw new Exception("Fizz got an exception.");
            }
        }

        static private void buzzLoop()
        {
            while (true)
            {
                //simulate something error prone, like some risky IO
                System.Threading.Thread.Sleep(200);
                bool isErr = (new Random().Next(1, 100) == 10);
                if (isErr)
                    throw new Exception("Buzz got an exception.");
            }
        }
    }
}

【问题讨论】:

标签: c# .net multithreading task-parallel-library task


【解决方案1】:

这可能是async void 方法很方便的少数情况之一:

static async void StartAndMonitorAsync(Func<Task> taskFunc)
{
    while (true)
    {
        var task = taskFunc();
        try
        {
            await task;
            // process the result if needed
            return;
        }
        catch (Exception ex)
        {
            // log the error
            System.Console.WriteLine("Error: {0}, restarting...", ex.Message);
        }
        // do other stuff before restarting (if any)
    }
}

static private void startLoops()
{
    System.Console.WriteLine("Starting fizzLoop.");
    StartAndMonitorAsync(() => Task.Factory.StartNew(new Action(fizzLoop)));

    System.Console.WriteLine("Starting buzzLoop.");
    StartAndMonitorAsync(() => Task.Factory.StartNew(new Action(buzzLoop)));
}

如果不能使用async/await,可以使用Task.ContinueWith实现类似的逻辑。

如果startLoops 可以被多次调用(而任务已经“进行中”),您需要使用CancelltionToken 将取消逻辑添加到StartAndMonitorAsync 和它所启动的任务中(更多详细信息见"A pattern for self-cancelling and restarting task")。

【讨论】:

    【解决方案2】:

    来自 MSDN “Task 基础结构将它们包装在一个 AggregateException 实例中。AggregateException 具有一个 InnerExceptions 属性,可以枚举该属性以检查所有引发的原始异常,并单独处理(或不处理)每个异常。即使只抛出一个异常,它仍然包含在 AggregateException 中。” 更多信息您可以check this

    try
    {
    System.Console.WriteLine("Starting fizzLoop.");
                var fizzTask = Task.Factory.StartNew(new Action(fizzLoop));
    
                System.Console.WriteLine("Starting buzzLoop.");
                var buzzTask = Task.Factory.StartNew(new Action(buzzLoop));
    
    }
    catch (AggregateException ae)
    {
        // Assume we know what's going on with this particular exception. 
        // Rethrow anything else. AggregateException.Handle provides 
        // another way to express this. See later example. 
        foreach (var e in ae.InnerExceptions)
        {
            if (e is MyCustomException)
            {
                Console.WriteLine(e.Message);
            }
            else
            {
                throw;
            }
        }
    
    }
    

    【讨论】:

    • 如果在启动新任务时发生异常,这将起作用。一旦任务启动并运行,我们就不再需要 try/catch 例程了。
    猜你喜欢
    • 2016-03-10
    • 2013-02-08
    • 1970-01-01
    • 2019-01-15
    • 1970-01-01
    • 1970-01-01
    • 2011-03-04
    • 2019-06-04
    • 2013-07-24
    相关资源
    最近更新 更多