数据流基础——传播错误
问题
假设需要对数据流网格中可能出现的错误做出响应
解决方案
如果传递至数据流块的委托抛出异常,则该快会进入错误状态,处于错误状态的块会丢弃其全部数据并停止接收新数据。一下代码中的块永远不会生成任何输出数据,第一个值会抛出异常,而第二个值会被丢弃:
var block=new TransformBlock<int,int>(item=>
{
if(item==1)
{
throw new InvalidOperationException("Blech.");
}
return item*2;
});
block.Post(1);
block.Post(2);
若要从数据流块中捕获异常,应当针对它的Completion属性应用await。当块完成时,Completion属性返回的Task也会完成。如果块出错,那么Completion任务也会出错:
try
{
var block=new TransformBlock<int,int>(item=>
{
if(item==1)
throw new InvalidOperationException("Blech.");
return item*2;
});
block.Post(1);
await block.Completion;
}
catch(InvalidOperationException)
{
//捕获异常
}
在使用PropagateCompletion选项传播完成状态时,也会传播错误。但是,异常会被包装在AggregateException中,传至下一个块。
讨论
在创建网格或管道时,考虑如何处理错误。在较为简单的情况下,最好传播错误并在最后一次性将他们全部捕获。在更为复杂的网格中,则可能需要在数据流完成时观察每个块。
如果在异常出现时,仍旧希望数据流块继续工作,那么可以把异常当做另一个种数据来处理,让他们跟着正确处理的数据项一起在网格中流动。使用这种模式,可以让数据流网格继续工作,这是因为块本身就不会出错,而会继续处理下一个数据项。