コード例 #1
0
        // Listing 13.#  Parallel Fork/Join using TPL DataFlow
        public static async Task <R> ForkJoin <T1, T2, R>(
            this IEnumerable <T1> source, Func <T1, Task <IEnumerable <T2> > > map,
            Func <R, T2, Task <R> > aggregate, R initialState,       // #A
            CancellationTokenSource cts = null,
            int partitionLevel          = 8, int boundCapacity = 20) // #B
        {
            cts = cts ?? new CancellationTokenSource();
            var blockOptions = new ExecutionDataflowBlockOptions
            {
                MaxDegreeOfParallelism = partitionLevel,
                BoundedCapacity        = boundCapacity,
                CancellationToken      = cts.Token
            }; // #C

            var inputBuffer = new BufferBlock <T1>(
                new DataflowBlockOptions
            {
                CancellationToken = cts.Token,
                BoundedCapacity   = boundCapacity
            });         // #D

            var mapperBlock  = new TransformManyBlock <T1, T2>(map, blockOptions);
            var reducerAgent = Agent.Start(initialState, aggregate, cts);
            var linkOptions  = new DataflowLinkOptions {
                PropagateCompletion = true
            };

            inputBuffer.LinkTo(mapperBlock, linkOptions);

            IDisposable disposable = mapperBlock.AsObservable()
                                     .Subscribe(async item => await reducerAgent.Send(item)); // #E

            foreach (var item in source)
            {
                await inputBuffer.SendAsync(item); // #F
            }
            inputBuffer.Complete();

            var tcs = new TaskCompletionSource <R>();

            await inputBuffer.Completion.ContinueWith(task => mapperBlock.Complete());

            await mapperBlock.Completion.ContinueWith(task =>
            {
                var agent = reducerAgent as StatefulDataflowAgent <R, T2>;
                disposable.Dispose();
                tcs.SetResult(agent.State);
            }); // #G

            return(await tcs.Task);
        }