如何在Parallel.Invoke中管理异常?

时间:2018-05-24 08:20:46

标签: c# multithreading

我有以下情况:

foreach(var item in collection)
{
    DoWork().Wait;
}

正如您所看到的,有一个foreach迭代一个集合,对于每个调用我需要等待DoWork完成执行,之后foreach可以继续。

问题在于DoWork我正在使用Parallel并且我得到一个异常“冻结”程序,特别是没有显示任何异常,这是我的实现:

public async Task DoWork()
{
    Try
    {
        Parallel.Invoke(
               () => Foo(),
               () => Foo2(),
               () => Foo3());
    }
    catch(Exception e)
    {
       //No exception caught
    }
}

我在Foo方法内添加了Console.WriteLine,例如:

public void Foo()
{
    Console.WriteLine("foo 1");
}

在方法Foo2内部生成了一个异常,但是我无法看到哪个异常,因为我在catch上设置了一个断点并且没有触发。

我做错了什么?

1 个答案:

答案 0 :(得分:4)

  1. 您的DoWork()方法不会异步运行,因为它没有任何调用 到await
  2. 当我尝试使用可编辑的代码版本时,我执行查看异常。
  3. 无论如何,如果您想让DoWork()正确异步,您需要使用Task.Run()await Task.WhenAll(),如下所示:

    using System;
    using System.Threading;
    using System.Threading.Tasks;                                                    
    
    namespace Demo
    {
        class Program
        {
            public static async Task Main()
            {
                Console.WriteLine("Awaiting DoWork()");
                await DoWork();
                Console.WriteLine("Finished awaiting. Press <RETURN> to exit.");
                Console.ReadLine();
            }
    
            public static async Task DoWork()
            {
                try
                {
                    await Task.WhenAll(
                        Task.Run(() => Foo()),
                        Task.Run(() => Foo2()),
                        Task.Run(() => Foo3())
                    );
                }
    
                catch (Exception e)
                {
                    Console.WriteLine("Caught exception: " + e.Message);
                }
            }
    
            public static void Foo()
            {
                Console.WriteLine("Starting Foo()");
                Thread.Sleep(1000);
                Console.WriteLine("Finishing Foo()");
            }
    
            public static void Foo2()
            {
                Console.WriteLine("Starting Foo2()");
                Thread.Sleep(500);
                Console.WriteLine("Foo2() is throwing an exception.");
                throw new InvalidOperationException("OOPS!");
            }
    
            public static void Foo3()
            {
                Console.WriteLine("Starting Foo3()");
                Thread.Sleep(250);
                Console.WriteLine("Finishing Foo3()");
            }
        }
    }
    

    如果编译并运行该代码,您将看到以下消息:

    waiting DoWork()
    Starting Foo()
    Starting Foo2()
    Starting Foo3()
    Finishing Foo3()
    Foo2() is throwing an exception.
    Finishing Foo()
    Caught exception: OOPS!
    Finished awaiting. Press <RETURN> to exit.
    

    请注意,此答案仅适用于C#7.1或更新版 Async Main