public async Task PerformProcessing(IEnumerable <string> files) { _readingCount = 0; _processingCount = 0; _writingCount = 0; NumberOfProcessingTasks.Clear(); NumberOfProcessingTasks.Clear(); NumberOfWritingTasks.Clear(); var linkOptions = new DataflowLinkOptions { PropagateCompletion = true }; var readingBlock = new TransformBlock <string, FileWithContent>( async path => new FileWithContent(path, await ReadFile(path)), new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = _pipelineConfiguration.MaxReadingTasks }); var processingBlock = new TransformBlock <FileWithContent, FileWithContent>( fwc => new FileWithContent(fwc.Path + ".processed", ProcessFile(fwc.Content)), new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = _pipelineConfiguration.MaxProcessingTasks }); var writingBlock = new ActionBlock <FileWithContent>(async fwc => await WriteFile(fwc), new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = _pipelineConfiguration.MaxWritingTasks }); readingBlock.LinkTo(processingBlock, linkOptions); processingBlock.LinkTo(writingBlock, linkOptions); foreach (string file in files) { readingBlock.Post(file); } readingBlock.Complete(); await writingBlock.Completion; }