为什么有时 ActionBlock 中的 Try/catch 没有捕捉到这个错误?

Why does Try/catch in ActionBlock not catch this error sometimes?

我正在编写的网络爬虫中使用 ActionBlock。

有时我打电话给

actionBlock.Completion.Wait();

我收到以下错误

One or more errors occurred.

内部例外是

System.Threading.Tasks.TaskCanceledException: A task was canceled.

这是下面的完整代码块。

actionBlock = new ActionBlock<URLsToCheckObject>(URLToCheck =>
{
    try
    {
        // get more urls etc here and post below

        actionBlock.Post(new URLsToCheckObject { URLAddress = CleanURL, Host = host });
        if (actionBlock.InputCount == 0) actionBlock.Complete();
    }
    catch (Exception ex)
    {
        try
        {
            Logger.AddToDebugLog("Block 3 catch...", WebsiteToCrawl);
        }
        catch { }
    }

}, new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 3, CancellationToken = cancellationSource.Token });

actionBlock.Post(new URLsToCheckObject { URLAddress = WebsiteToCrawl.website, Host = host });

try
{
    Logger.AddToDebugLog("Waiting on action block..", WebsiteToCrawl);
    actionBlock.Completion.Wait();
}
catch (Exception ex)
{
    try
    {
        Logger.AddToDebugLog("Block 4 catch..." + ex.Message, WebsiteToCrawl);
    }
    catch { }

    try
    {
        Logger.AddToDebugLog("Block 4 catch..." + ex.InnerException, WebsiteToCrawl);
    }
    catch { }

    try
    {
        Logger.AddToDebugLog("Block 4 catch...", WebsiteToCrawl);
    }
    catch { }
}

为什么包裹 ActionBlock 全部内容的 try/catch 没有捕捉到这个异常?

在进入try之前开始动作,会不会异常发生的太早了?

actionBlock.Post(new URLsToCheckObject { URLAddress = WebsiteToCrawl.website, Host = host }); 移到 try catch

ActionBlock<> 可以安排处理您 Post 处理的所有项目。因此,要执行的代码比您在 lambda 中实现的要多。 (就像 Parallel.ForEachTask.Run() 比您传递的代码要执行的更多)。

ActionBlock<> 必须等待传入的元素,因此还要检查是否应该取消它。即使有传入的项目,它也会检查是否在调用您的代码之前请求取消,因此您的try块之外。

因此,如果在块仅等待项目时请求取消,但当前未在您的 lambda 中处理项目,则您无法捕获异常。

异常通常来自:

cancellationToken.ThrowIfCancellationRequested();

因为您没有在 lambda 中使用 CancellationToken,但它用作以下参数:

new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 3, CancellationToken = cancellationSource.Token }

TaskCanceledException 不是来自你的 lambda(但可能来自 ExecutionDataflowBlockOptionsActionBlock 内部)所以它在你的 try/catch 范围之外lambda,所以它没有捕获。