TPL Dataflow管道设计基础知识

时间:2014-03-10 10:15:43

标签: .net task-parallel-library pipeline tpl-dataflow

我尝试使用系统资源的最佳使用来创建设计良好的TPL数据流管道。我的项目是一个HTML解析器,它将解析后的值添加到SQL Server DB中。我已经拥有了我未来管道的所有方法,现在我的问题是将它们放在Dataflow块中的最佳方法是什么,以及我应该使用多少块?一些方法是CPU绑定的,其中一些方法 - I / O绑定(从Internet加载,SQL Server数据库查询)。现在我认为将每个I / O操作放在单独的块中就像这个方案一样正确:     TPL Dataflow pipeline

在这种情况下设计管道的基本规则是什么?

2 个答案:

答案 0 :(得分:6)

选择如何划分块的一种方法是决定要独立于其他部分进行缩放的部分。一个好的起点是将CPU绑定部分与I / O绑定部分分开。我考虑组合最后两个块,因为它们都是I / O绑定的(大概是相同的数据库)。

答案 1 :(得分:0)

我从Concurrent Programming on Windows发布了一个示例常规管道。良好的管道是平衡的管道,这意味着每个阶段都不能在管道内瓶颈。基于示例代码,您可以创建执行每个阶段的线程数。

源代码:

public class Pipeline<TSource, TDest> : IPipeline
{
  private readonly IPipelineStage[] _stages;

  public Pipeline(Func<TSource, TDest> transform, int degree) : 
     this (new IPipelineStage[0], transform, degree) {}

  internal Pipeline(IPipelineStage[] toCopy, Func<TSource, TDest> transform, int degree) 
  {
     _stages = new IPipelineStage[toCopy.Length] + 1;
     Array.Copy(toCopy, _stages, _stages.Length);
     _stages[_stages.Length - 1] = new PipelineStage(transform, degree);
  }

  public Pipeline<TSource, TNew> AddStage<TNew>(Func<TDest, TNew> transform, degree) 
  {
     return new Pipeline<TSource, TNew>(_stages, transform, degree);
  }

  public IEnumerator<TDest> GetEnumerator(IEnumerable<TSrouce> arg)
  {
     IEnumerable er = arg;
     CountdownEvent ev = null;

     for (int i = 0; i < _stages.Length; i++)
       er = _stages[i].Start(er, ref ev);

     foreach (TDest elem in ef)
       yield return elem;
  }
}

class PipelineStage<TInput, TOutput> : IPipelineStage
{
   private readonly Func<TInput, TOutput> _transform;
   private readonly int _degree;

   internal PipelineStage(Func<TInput, TOutput> transform, int degree)
   {
      _transform = transform;
      _degree = degree;
   }

   internal IEnumerable Start(IEnumerable src)
   {
       //...
   }
}

interface IPipelineStage 
{
   IEnumerable Start(IEnumerable Src);
}