【问题标题】:Why does Try/catch in ActionBlock not catch this error sometimes?为什么 ActionBlock 中的 Try/catch 有时无法捕捉到这个错误?
【发布时间】:2019-09-04 08:13:19
【问题描述】:

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

有时当我打电话时

actionBlock.Completion.Wait();

我收到以下错误

发生了一个或多个错误。

内部异常是

System.Threading.Tasks.TaskCanceledException:任务被取消。

这是下面的完整代码块。

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 不能捕捉到这个异常?

【问题讨论】:

  • 您正在其自己的委托中操纵ActionBlock。我不认为这个类被设计成这样使用。如果您想创建一个循环,其中管道的末端向管道添加更多元素,您可能应该在ActionBlock 之前使用链接的BufferBlock,并将ActionBlock 发布到BufferBlock
  • @jamie 这不是 Dataflow 块应该如何工作。这段代码本质上是一个无限循环,它将 ActionBlock 视为一个队列。您不会告诉块从 内部 完成,它会在上游块完成时自动完成。如果要生成更多 URL,请在上一步中进行。代码根本不必那么复杂

标签: c# task-parallel-library tpl-dataflow


【解决方案1】:

异常通常来自:

cancellationToken.ThrowIfCancellationRequested();

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

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

TaskCanceledException 不是来自您的 lambda(但可能来自 ExecutionDataflowBlockOptionsActionBlock 内部),因此它超出了 lambda 内的 try/catch 范围,因此它不会捕获。

【讨论】:

    【解决方案2】:

    ActionBlock&lt;&gt; 用于安排处理您 Post 处理的所有项目。因此,要执行的代码比您在 lambda 中实现的代码要多。 (就像Parallel.ForEachTask.Run() 比您传递的代码要执行的更多)。

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

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

    【讨论】:

      【解决方案3】:

      在进入try之前就开始action,会不会是异常发生得太快了?

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

      【讨论】:

        猜你喜欢
        • 2021-07-25
        • 2017-07-25
        • 1970-01-01
        • 2013-02-05
        • 2016-01-26
        • 2021-07-25
        相关资源
        最近更新 更多