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;
}
}