C# Concurrent Framework(TDF),这里是否需要集合的深度副本?

C# Concurrent Framework(TDF),这里是否需要集合的深度副本?,c#,collections,concurrency,cloning,tpl-dataflow,C#,Collections,Concurrency,Cloning,Tpl Dataflow,我对传递到广播块的列表集合有问题。以下是我到目前为止得到的(伪代码,因为完整的代码库太长): 我可能会将Quote[]而不是List馈送到广播块中,但我看不出这有助于加快深度拷贝的性能 我的问题是: 深度复制问题是这里真正的问题吗(我怀疑,因为流到广播块中的列表,从未被任何转换块改变过) 如果是,为什么以及如何使深度拷贝更高效 我回答自己的问题,因为我最终解决了这个问题。svick提醒的问题与List是否需要广播块中的深度副本无关(事实上,它不需要深度副本)。问题与batchBlock之前请求

我对传递到广播块的列表集合有问题。以下是我到目前为止得到的(伪代码,因为完整的代码库太长):

我可能会将
Quote[]
而不是
List
馈送到广播块中,但我看不出这有助于加快深度拷贝的性能

我的问题是:

  • 深度复制问题是这里真正的问题吗(我怀疑,因为流到广播块中的
    列表
    ,从未被任何转换块改变过)
  • 如果是,为什么以及如何使深度拷贝更高效

    • 我回答自己的问题,因为我最终解决了这个问题。svick提醒的问题与
      List
      是否需要广播块中的深度副本无关(事实上,它不需要深度副本)。问题与batchBlock之前请求完成的broadcastBlock有关(对于链接的数据流块,完整传播设置为true),batchBlock也链接到joinBlock,可能将所有项目流式传输到joinBlock。我只是删除了joinBlock,因为我重写了转换块(它们现在返回自己的转换项以及原始项,并使joinBlock过时)

      请注意主transformBlock中的并发性:将MaxDegreeOfParallelism设置为>1已经提供了性能优势,即使是在这种较轻的工作负载下,但是,当向它抛出较重的工作负载时,它确实起到了作用

      这里是编译和运行的完整代码(我重命名了一些类,但结构仍如所述):

      公共类测试
      {
      私人秒表;
      专用广播块tempbcbcb;
      专用批块批块;
      私有转换块转换块;
      私有操作块justtoflusionblock;
      私有corelogiccore1;
      私有corelogiccore2;
      公开考试()
      {
      tempBCB=新广播块(输入=>输入);
      //此处批量大小=2
      batchBlock=new batchBlock(2,new GroupingDataflowBlockOptions{贪婪=false});
      transformBlock=新transformBlock(数组=>
      {
      列表inputObjects=array[0]。项1;
      List ret=inputObject.ConvertAll(x=>newfinalobject(x));
      foreach(数组中的变量元组)
      {
      //迭代每个单独的对象
      foreach(tuple.Item2中的var字典)
      {
      ret[dictionary.Key].outputList.Add(dictionary.Value);
      }
      }
      返回ret;
      },新的ExecutionDataflowBlockOptions{MaxDegreeOfParallelism=DataflowBlockOptions.Unbounded});
      justToFlushTransformBlock=新操作块(列表=>
      {
      //只是为了接受transformBlock输出队列中的项目
      });
      //生成2个CoreLogic对象
      core1=新的CoreLogic();
      core2=新的CoreLogic();
      //连接
      LinkTo(core1.transformBlock,新数据流链接选项{PropagateCompletion=true});
      LinkTo(core2.transformBlock,新数据流链接选项{PropagateCompletion=true});
      core1.transformBlock.LinkTo(批块);
      core2.transformBlock.LinkTo(批块);
      LinkTo(transformBlock,新的DataflowLinkOptions{PropagateCompletion=true});
      LinkTo(justToFlushTransformBlock,新数据流链接选项{PropagateCompletion=true});
      }
      公开作废开始()
      {
      常数int numberChunks=30;
      手表=新秒表();
      watch.Start();
      对于(int j=1;j
      {
      batchBlock.Complete();
      });
      transformBlock.Completion.Wait();
      看,停;
      Console.WriteLine(“运行时间(毫秒):”+watch.elapsedmillesons);
      Console.ReadLine();
      }
      }
      公共类核心逻辑
      {
      私有随机兰德;
      公共转换块转换块;
      公共核心逻辑()
      {
      常数int numberntermediateobjects=10000;
      transformBlock=新transformBlock(输入=>
      {
      //请忽略以下事实:此处未使用'input',重点是生成一个IntermediateObject和return的集合
      字典ret=新字典();
      对于(int i=0;i

      我希望这能帮助其他可能遇到类似问题的人。我喜欢TPL Dataflow,特别是svick确实帮助并激励了我深入挖掘。谢谢svick!!!

      我回答了我自己的问题,因为我解决了这个问题
      private BroadcastBlock<List<Quote>> tempBCB;
      private TransformBlock<List<Quote>, Dictionary<int, IParentOrder>> tfb1;
      private TransformBlock<List<Quote>, Dictionary<int, IParentOrder>> tfb2;
      private BatchBlock<Dictionary<int, IParentOrder>> batchBlock;
      private JoinBlock<List<Quote>, Dictionary<int, IParentOrder>[]> joinBlock;
      private TransformBlock<Tuple<List<Quote>, 
          Dictionary<int, IParentOrder>[]>,List<MySignal>> transformBlock;
      
      tempBCB = new BroadcastBlock<List<Quote>>(quoteList => {
          return quoteList;
          //return Cloning.CloneListCloneValues<Quote>(quoteList);
      });
      
      tfb1 = new TransformBlock<List<Quote>, Dictionary<int, IParentOrder>>(
          quotes => {//do something and return Dictionary<int, IParentOrder>});
      
      tfb2 = new TransformBlock<List<Quote>, Dictionary<int, IParentOrder>>(
          quotes => {//do something and return Dictionary<int, IParentOrder>});
      
      batchBlock = new BatchBlock<Dictionary<int, IParentOrder>>(2);
      
      joinBlock = new JoinBlock<List<Quote>, Dictionary<int, IParentOrder>[]>(
          new GroupingDataflowBlockOptions { Greedy = false });
      
      transformBlock = new TransformBlock<Tuple<List<Quote>, 
          Dictionary<int, IParentOrder>[]>, List<MySignal>>(
          tuple => { //do something and return List<MySignal>;});
      
      //Linking
      tempBCB.LinkTo(tfb1);
      tempBCB.LinkTo(tfb2);
      tfb1.LinkTo(batchBlock);
      tfb2.LinkTo(batchBlock);
      tempBCB.LinkTo(joinBlock.Target1);
      batchBlock.LinkTo(joinBlock.Target2);
      joinBlock.LinkTo(transformBlock);
      
      public static List<TValue> CloneListCloneValues<TValue>(List<TValue> original) 
          where TValue : ICloneable
      {
          List<TValue> ret = new List<TValue>(original.Count);
      
          foreach (TValue entry in original)
          {
              ret.Add((TValue)entry.Clone());
          }
      
          return ret;
      }
      
      public class Test
      {
          private Stopwatch watch;
      
          private BroadcastBlock<List<InputObject>> tempBCB;
          private BatchBlock<Tuple<List<InputObject>, Dictionary<int, IntermediateObject>>> batchBlock;
          private TransformBlock<Tuple<List<InputObject>, Dictionary<int, IntermediateObject>>[], List<FinalObject>> transformBlock;
          private ActionBlock<List<FinalObject>> justToFlushTransformBlock;
      
          private CoreLogic core1;
          private CoreLogic core2;
      
          public Test()
          {
              tempBCB = new BroadcastBlock<List<InputObject>>(input => input);
      
              //here batch size = 2
              batchBlock = new BatchBlock<Tuple<List<InputObject>,Dictionary<int,IntermediateObject>>>(2, new GroupingDataflowBlockOptions { Greedy = false });
      
              transformBlock = new TransformBlock<Tuple<List<InputObject>,Dictionary<int,IntermediateObject>>[],List<FinalObject>>(array =>
              {
                  List<InputObject> inputObjects = array[0].Item1;
                  List<FinalObject> ret = inputObjects.ConvertAll(x => new FinalObject(x));
      
                  foreach (var tuple in array)
                  {
                      //iterate over each individual object
                      foreach (var dictionary in tuple.Item2)
                      {
                          ret[dictionary.Key].outputList.Add(dictionary.Value);
                      }
                  }
      
                  return ret;
              }, new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = DataflowBlockOptions.Unbounded });
      
              justToFlushTransformBlock = new ActionBlock<List<FinalObject>>(list =>
                  {
                      //just in order to accept items from the transformBlock output queue
                  });
      
              //Generate 2 CoreLogic objects
              core1 = new CoreLogic();
              core2 = new CoreLogic();
      
              //linking
              tempBCB.LinkTo(core1.transformBlock, new DataflowLinkOptions { PropagateCompletion = true });
              tempBCB.LinkTo(core2.transformBlock, new DataflowLinkOptions { PropagateCompletion = true });
      
              core1.transformBlock.LinkTo(batchBlock);
              core2.transformBlock.LinkTo(batchBlock);
      
              batchBlock.LinkTo(transformBlock, new DataflowLinkOptions { PropagateCompletion = true });
      
              transformBlock.LinkTo(justToFlushTransformBlock, new DataflowLinkOptions { PropagateCompletion = true });
          }
      
          public void Start()
          {
              const int numberChunks = 30;
      
              watch = new Stopwatch();
              watch.Start();
      
              for (int j = 1; j <= numberChunks; j++)
              {
                  int collectionSize = 10000 * j;
      
                  List<InputObject> collection = new List<InputObject>(collectionSize);
                  for (int i = 0; i < collectionSize; i++)
                  {
                      collection.Add(new InputObject(i));
                  }
      
                  tempBCB.Post(collection);
              }
      
              tempBCB.Complete();
      
              Task.WhenAll(core1.transformBlock.Completion, core2.transformBlock.Completion).ContinueWith(_ =>
                  {
                      batchBlock.Complete();
                  });
      
              transformBlock.Completion.Wait();
      
              watch.Stop();
      
              Console.WriteLine("Elapsed time (in milliseconds): " + watch.ElapsedMilliseconds);
              Console.ReadLine();
          }
      }
      
      public class CoreLogic
      {
          private Random rand;
          public TransformBlock<List<InputObject>, Tuple<List<InputObject>, Dictionary<int, IntermediateObject>>> transformBlock;
      
          public CoreLogic()
          {
              const int numberIntermediateObjects = 10000;
      
              transformBlock = new TransformBlock<List<InputObject>, Tuple<List<InputObject>, Dictionary<int, IntermediateObject>>>(input =>
              {
                  //please ignore the fact that `input` is not utilized here, the point is to generate a collection of IntermediateObject and return
      
                  Dictionary<int, IntermediateObject> ret = new Dictionary<int, IntermediateObject>();
                  for (int i = 0; i < numberIntermediateObjects; i++)
                  {
                      IntermediateObject value = new IntermediateObject(i);
      
                      ret.Add(i, value);
                  }
      
                  var tuple = new Tuple<List<InputObject>, Dictionary<int, IntermediateObject>>(input, ret);
      
                  return tuple;
              });
          }
      }
      
      public class InputObject : ICloneable
      {
          public int value1 { get; private set; }
      
          public InputObject(int value)
          {
              this.value1 = value;
          }
      
          object ICloneable.Clone()
          {
              return Clone();
          }
      
          public InputObject Clone()
          {
              return (InputObject)this.MemberwiseClone();
          }
      }
      
      public class IntermediateObject
      {
          public int value1 { get; private set; }
      
          public IntermediateObject(int value)
          {
              this.value1 = value;
          }
      }
      
      public class FinalObject
      {
          public InputObject input { get; private set; }
          public List<IntermediateObject> outputList;
      
          public FinalObject(InputObject input)
          {
              this.input = input;
      
              this.outputList = new List<IntermediateObject>();
          }
      }
      
      public static class Cloning
      {
          public static List<TValue> CloneListCloneValues<TValue>(List<TValue> original) where TValue : ICloneable
          {
              List<TValue> ret = new List<TValue>(original.Count);
      
              foreach (TValue entry in original)
              {
                  ret.Add((TValue)entry.Clone());
              }
      
              return ret;
          }
      }