我正在尝试获取大约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)
{
???
}
答案 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
}
});
但是您遇到的问题不止于此。
Parallel.ForEach
documents.Add
看起来不是线程安全的说实话,这确实是 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;
}
}