Dataflow with splitting work to small jobs and then group again

后端 未结 3 1083
终归单人心
终归单人心 2020-12-31 09:36

I need to do this kind of work:

  1. Get Page object from database
  2. For each page get all images and process them (IO bound, for example, upload to CDN)
3条回答
  •  一向
    一向 (楼主)
    2020-12-31 09:56

    You can group the images together by recording whenever an image for a given page arrives and then sending the page on when all images arrived. To figure that out, page needs to know how many images it contains, but I assume you know that.

    In code, it could look something like this:

    public static IPropagatorBlock
        CreaterMergerBlock(
        Func getMergedFunc, Func getSplitCount)
    {
        var dictionary = new Dictionary();
    
        return new TransformManyBlock(
            split =>
            {
                var merged = getMergedFunc(split);
                int count;
                dictionary.TryGetValue(merged, out count);
                count++;
                if (getSplitCount(merged) == count)
                {
                    dictionary.Remove(merged);
                    return new[] { merged };
                }
    
                dictionary[merged] = count;
                return new TMerged[0];
            });
    }
    

    Usage:

    var dataPipe = new BufferBlock();
    
    var splitter = new TransformManyBlock(
        page => page.LoadImages(),
        new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 8 });
    
    var processImage = new TransformBlock(
        image =>
        {
            // process the image here
            return image;
        }, new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 8 });
    
    var merger = CreaterMergerBlock(
        (ImageWithPage image) => image.Page, page => page.ImageCount);
    
    var savePage = new ActionBlock(
        page => /* save the page here */,
        new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 5 });
    
    dataPipe.LinkTo(splitter);
    splitter.LinkTo(processImage);
    processImage.LinkTo(merger);
    merger.LinkTo(savePage);
    

提交回复
热议问题