在可能的情况下获取数据时处理异常

时间:2014-12-30 14:14:15

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

以下是我用来从多个网址检索数据的代码。对于几个网址,我得到了例外,但对于其他所有网址,我都获得了有效的数据。问题是,对于下面的apporoach,我无法收集能够无任何问题地检索数据的线程的数据。反正收集尽可能多的url响应,同时还知道哪些url会抛出异常?

static void Main(string[] args)
{
    var URLsToProcess = new List<string>
            {
                "http://www.microsoft.com",
                "http://www.stackoverflow.com",
                "http://www.google.com",
                "http://www.apple.com",
                "http://www.ebay.com",
                "http://www.oracle.com",
                "http://www.gmail.com",
                "http://www.amazon.com",
                "http://www.outlook.com",
                "http://www.yahoo.com",
                "http://www.amazon124.com",
                "http://www.msn.com"
                };

    string[] tURLs = null;
    try
    {
        tURLs = URLsToProcess
            .AsParallel()
            .WithDegreeOfParallelism(3)
            .Select(uri => DownloadStringAsTask(new Uri(uri)).Result)
            .ToArray();
    }
    catch (AggregateException ex)
    {
        AggregateException exf =  ex.Flatten();

    }
    Console.WriteLine("download all done");
    if (tURLs != null)
    {
        foreach (string t in tURLs)
        {
            Console.WriteLine(t);
        }
    }
}

static Task<string> DownloadStringAsTask(Uri address)
{
    TaskCompletionSource<string> tcs =
      new TaskCompletionSource<string>();
    WebClient client = new WebClient();
    client.DownloadStringCompleted += (sender, args) =>
    {
        if (args.Error != null) 
            tcs.SetException(args.Error);
        else if (args.Cancelled) 
            tcs.SetCanceled();
        else 
            tcs.SetResult(args.Result);
    };
    client.DownloadStringAsync(address);
    return tcs.Task;
}

1 个答案:

答案 0 :(得分:2)

是的,有:

var tasks = URLsToProcess.Select(uri => DownloadStringAsTask(new Uri(uri))).ToArray();

while (tasks.Any())
{
    try
    {
        Task.WaitAll(tasks);
        break;
    }
    catch (Exception e)
    {
        // handle exception/report progress...
        tasks = tasks.Where(t => t.Status != TaskStatus.Faulted).ToArray();
    }
}

var results = tasks.Select(t => t.Result);

使用Task.WaitAll等待(同步,因为async-await不可用)同时完成所有任务。如果Task.WaitAll成功完成,请跳出while循环并使用Task.Result提取结果。如果有异常,请删除故障任务并再次等待其他任务,等等。