TPL Dataflow: Design for parallelism while maintaining order

I have never worked with TPL before, so I was wondering if this can be done: My application creates a gif image animation file from multiple frames. I start with the Bitmap list, which represents the frames of the gif file, and for each frame you need to do the following:

  • draw a series of frames / bitmaps on a frame
  • crop frame
  • resize frame
  • reduce image to 256 colors

Obviously, this process can be performed in parallel for all frames in the list, but for each frame, the order of steps should be the same. After that I need to write all the frames to the gif file. Therefore, all frames must be received in the same order in which they were in the original list. In addition, this process can begin when the first frame is ready for this, there is no need to wait until all frames are processed.

So the situation. Is the TPL data stream suitable for this? If so, can someone give me a hint in the right direction on how to create a tpl block structure to reflect the process described above? It seems pretty complicated to me compared to some of the samples I found.

+4
3

, TPL Dataflow , , , parallelism.

, , , :

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)
{
}
+4

, , DataFlow - . TransformBlock. . , bufferblock .

, transformblock msdn:

+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
+2
source

Source: https://habr.com/ru/post/1524982/


All Articles