C#中出现异常后继续

时间:2019-02-26 11:07:03

标签: c# exception web-scraping try-catch parallel.foreach

我正在尝试获取大约docdoc的文档类型。 3k链接。但是当它达到700-900标记线时,我总是会遇到异常。

如何在发生异常的地方继续(因此我没有义务再次从零开始)?那有可能吗?

这是我使用的代码:

     try
        {
            Parallel.ForEach(linkList, link => 
            {
                stopwatch.Restart();
                Console.Write($"Downloading page {index++} of {linkList.Count}...");
                documents.Add(LoadPage(link));
                Console.Write($" in {stopwatch.Elapsed.TotalMilliseconds} ms");
                Console.WriteLine();
            });

            return documents;
        }
        catch (Exception e)
        {
            ???
        }

3 个答案:

答案 0 :(得分:1)

尝试将内部代码包装在try-catch中

        Parallel.ForEach(linkList, link => 
        {
            try
            {
                stopwatch.Restart();
                Console.Write($"Downloading page {index++} of {linkList.Count}...");
                documents.Add(LoadPage(link));
                Console.Write($" in {stopwatch.Elapsed.TotalMilliseconds} ms");
                Console.WriteLine();
            }
            catch (Exception e)
            {
                ???
            }
        });

        return documents;

编辑:

您可能还想看看C#必须提供的thread-safe collections,因为普通的集合不是线程安全的

答案 1 :(得分:0)

您只需要在ForEach

中处理它们
Parallel.ForEach(linkList, link => 
{
    try
    {
       ...
     }
     catch(Exception ex)
     {
        // log
     }
});

但是您遇到的问题不止于此。

  1. 这看起来像IO限制的工作负载,不适合Parallel.ForEach
  2. documents.Add看起来不是线程安全的
  3. 您的索引将消失

说实话,这确实是 TPL数据流的工作,它为您带来了与 async and await 和IO约束的工作负载很好地协同工作的好处。使用 async and await ,将不再影响Task Scheduler,让IO完成端口执行其工作以释放线程池。

它还将使您能够创建更复杂的管道,并在需要时能够将失败的作业重新提供给它自己,还有许多其他优点

答案 2 :(得分:0)

伙计们,那就是使我达到目标的解决方案。

        var index = 1;
        Parallel.ForEach(linkList,  link => { GetDocuments(stopwatch, index++, linkList, documents, link); });

        if (FailedDownloads.Count > 0)
        {
            linkList = new List<string>(FailedDownloads);
            FailedDownloads.Clear();
            Parallel.ForEach(linkList,
                link => { GetDocuments(stopwatch, index++, linkList, documents, link); });
        }
        return documents;
    }

    private void GetDocuments(Stopwatch stopwatch, int index, List<string> linkList, List<HtmlDocument> documents, string link)
    {
        stopwatch.Restart();
        Console.Write($"Downloading page {index} of {linkList.Count}...");
        try
        {
            documents.Add(LoadPage(link));
            Console.Write($" in {stopwatch.Elapsed.TotalMilliseconds} ms");
        }
        catch (AggregateException e)
        {
            if (e.InnerExceptions[0] is HttpRequestException)
            {
                FailedDownloads.Add(link);
                Console.WriteLine(e);
            }
            else
            {
                throw;
            }
        }