之前我从未使用过TPL,所以我想知道是否可以用它完成: 我的应用程序从很多帧创建一个gif图像动画文件。我从一个Bitmap列表开始,它代表了gif文件的帧,需要为每个帧执行以下操作:
显然,这个过程可以对列表中的所有帧并行完成,但对于每个帧,步骤的顺序必须相同。 之后,我需要将所有帧写入gif文件。因此,需要以与原始列表中相同的顺序接收所有帧。最重要的是,此过程可以在第一帧准备就绪时开始,无需等到所有帧都被处理完毕。
这就是情况。 TPL Dataflow适合这个吗?如果是的话,任何人都可以给我一个关于如何设计tpl块结构以反映上述过程的正确方向的提示吗?与我发现的一些样品相比,这对我来说似乎相当复杂。
答案 0 :(得分:4)
我认为使用TPL Dataflow是有道理的,特别是因为即使启用了并行性,它也会自动保持处理元素的正确顺序。
您可以为流程中的每个步骤创建一个单独的块,但我认为这里没有必要,一个用于处理帧的块和一个用于编写它们的块就足够了:
public Task CreateAnimationFileAsync(IEnumerable<Bitmap> frames)
{
var frameProcessor = new TransformBlock<Bitmap, Bitmap>(
frame => ProcessFrame(frame),
new ExecutionDataflowBlockOptions
{ MaxDegreeOfParallelism = DataflowBlockOptions.Unbounded });
var animationWriter = new ActionBlock<Bitmap>(frame => WriteFrame(frame));
frameProcessor.LinkTo(
animationWriter,
new DataflowLinkOptions { PropagateCompletion = true });
foreach (var frame in frames)
{
frameProcessor.Post(frame);
}
frameProcessor.Complete();
return animationWriter.Completion;
}
private Bitmap ProcessFrame(Bitmap frame)
{
…
}
private async Task WriteFrame(Bitmap frame)
{
…
}
答案 1 :(得分:2)
我认为你会发现DataFlow
是正确的方法。对于每个帧,从您的帧列表中,尝试创建一个TransformBlock
。对于四个步骤中的每个步骤,以正确的顺序将帧链接在一起。如果要同时处理框架列表,可以使用bufferblock
作为框架列表。
please find the full sample on how to use transformblock on msdn:
答案 2 :(得分:2)
您的问题是数据流优势所在的完美示例。
这是最简单的代码,可以帮助您入门。
// Try increasing MaxDegreeOfParallelism
var opt = new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 2 };
// Create the blocks
// You must define the functions to do what you want
var paintBlock = new TransformBlock<Bitmap, Bitmap>(fnPaintText, opt);
var cropBlock = new TransformBlock<Bitmap, Bitmap>(fnCrop, opt);
var resizeBlock = new TransformBlock<Bitmap, Bitmap>(fnResize, opt);
var reduceBlock = new TransformBlock<Bitmap, Bitmap>(fnReduce,opt);
// Link the blocks together
paintBlock.LinkTo(cropBlock);
cropBlock.LinkTo(resizeBlock);
resizeBlock.LinkTo(reduceBlock);
// Send data to the first block
// ListOfImages contains your original frames
foreach (var img in ListOfImages) {
paintBlock.Post(img);
}
// Receive the modified images
var outputImages = new List<Bitmap>();
for (int i = 0; i < ListOfImages.Count; i++) {
outputImages.Add(reduceBlock.Receive());
}
// outputImages now holds all of the frames
// reassemble them in order