zoukankan      html  css  js  c++  java
  • Effective C# 学习笔记(三十七) 警惕并行处理中的异常处理

    若一个异常到达了调用该线程的方法时,该线程也就终止运行了。而并行编程使用AggregateException类型来处理发生在子线程中的各类异常,而这些异常存储在AggregateException对象的InnerExceptions属性中。处理异常策略的原则是:处理你能恢复到正常状态的异常,抛出其他那些异常。

     

    下面的代码,是修改上一次笔记中说明Web下载逻辑。使用一个Dictionary结构来处理异常,其键值分别为异常类型(Exception Type)和处理的代理(Action<T>)。

    //异常处理段代码

    try

    {

    urls.RunAsync(url => startDownload(url),

    task => finishDownload(task.AsyncState.ToString(),

    task.Result));

    }

    catch (AggregateException problems)

    {

    //注册处理各类异常的逻辑

    var handlers = new Dictionary<Type, Action<Exception>>();

    handlers.Add(typeof(WebException),ex => Console.WriteLine(ex.Message));

    if (!HandleAggregateError(problems, handlers))

    throw;//这里抛出了AggregateException,而不是具体的异常,因为InnerExceptions中可能有你需要的其他异常信息。

    }

     

    //处理异常的方法

    private static bool HandleAggregateError(AggregateException aggregate,

    Dictionary<Type, Action<Exception>> exceptionHandlers)

    {

    foreach (var exception in aggregate.InnerExceptions)

    //递归处理所有的内部异常

    if (exception is AggregateException)

    return HandleAggregateError(

    exception as AggregateException, exceptionHandlers);

    //若包含处理方法,处理之

    else if (exceptionHandlers.ContainsKey( exception.GetType()))

    {

    exceptionHandlers[exception.GetType()] (exception);

    }

    //否则处理不了,返回false

    else

    return false;

    return true;

    }

     

    在大多数情况下,处理已知异常,而不是抛出它,不处理它更合适。所以我们修改了开始下载处理逻辑部分的代码:

    private static Task<byte[]> startDownload(string url)

    {

    var tcs = new TaskCompletionSource<byte[]>(url);

    var wc = new WebClient();

    wc.DownloadDataCompleted += (sender, e) =>

    {

    if (e.UserState == tcs)

    {

    if (e.Cancelled)

    tcs.TrySetCanceled();

    else if (e.Error != null)

    {

    if (e.Error is WebException)//当发生WebException时,将结果设置为0字节

    tcs.TrySetResult(new byte[0]);

    else//其他异常情况

    tcs.TrySetException(e.Error);

    }

    else//正常情况

    tcs.TrySetResult(e.Result);

    }

    };

    wc.DownloadDataAsync(new Uri(url), tcs);

    return tcs.Task;

    }

    上面的代码在处理WebException时,只返回0字节,表示下载的失败,因为该异常明确的说明了服务地址的不可达。

     

    由于Query查询只在有代码访问其结果集的时候会执行,所以不必在定义Query的地方加入try/catch区块,你只需在执行获取Query结果集的部分执行即可。如下代码:

    var nums = from n in data

    where n < 150

    select Factorial(n);

    try

    {

    foreach (var item in nums)

    Console.WriteLine(item);

    }

    catch (InvalidOperationException inv)

    {

    // elided

    }

     

    而在使用PLINQ时,由于其执行顺序的不同,你需要把定义Query的部分也try/catch起来,而你捕获的异常要用AggregateException多线程并发异常类,其内部属性InnerExceptions会返回你要的内部异常,其是由Parallel Task Library提供专门用来处理并发运行中的异常的。若任何一个后台线程抛出异常,整个的后台操作也就停止了。所以你要做的是尽量确保后台不抛出异常,并处理AggregateException异常。

  • 相关阅读:
    HDU 1495 非常可乐
    ja
    Codeforces Good Bye 2016 E. New Year and Old Subsequence
    The 2019 Asia Nanchang First Round Online Programming Contest
    Educational Codeforces Round 72 (Rated for Div. 2)
    Codeforces Round #583 (Div. 1 + Div. 2, based on Olympiad of Metropolises)
    AtCoder Regular Contest 102
    AtCoder Regular Contest 103
    POJ1741 Tree(点分治)
    洛谷P2634 [国家集训队]聪聪可可(点分治)
  • 原文地址:https://www.cnblogs.com/haokaibo/p/2117783.html
Copyright © 2011-2022 走看看