コード例 #1
0
		public void BasicUsageTest ()
		{
			Tuple<IList<int>, IList<int>, IList<string>> result = null;
			var evt = new ManualResetEventSlim (false);

			var actionBlock =
				new ActionBlock<Tuple<IList<int>, IList<int>, IList<string>>> (r =>
				{
					result = r;
					evt.Set ();
				});
			var block = new BatchedJoinBlock<int, int, string> (3);

			block.LinkTo (actionBlock);

			// all targets once
			Assert.IsTrue (block.Target1.Post (1));
			Assert.IsTrue (block.Target2.Post (2));

			Assert.IsFalse (evt.Wait (100));
			Assert.IsNull (result);

			Assert.IsTrue (block.Target3.Post ("foo"));

			Assert.IsTrue (evt.Wait (1000));

			Assert.IsNotNull (result);
			CollectionAssert.AreEqual (new[] { 1 }, result.Item1);
			CollectionAssert.AreEqual (new[] { 2 }, result.Item2);
			CollectionAssert.AreEqual (new[] { "foo" }, result.Item3);
		}
コード例 #2
0
        public void Run()
        {
            var broadcastBlock = new BroadcastBlock <int>(a => a);

            var a1 = new TransformBlock <int, int>(a =>
            {
                Console.WriteLine($"Mesaj {a} a1 tarafından işlenilmekte.");
                Task.Delay(300).Wait();
                if (a % 2 == 0)
                {
                    Task.Delay(300).Wait();
                }
                else
                {
                    Task.Delay(50).Wait();
                }
                return(-a);
            }, new ExecutionDataflowBlockOptions()
            {
                MaxDegreeOfParallelism = 3
            });


            var a2 = new TransformBlock <int, int>(a =>
            {
                Console.WriteLine($"Mesaj {a} a2 tarafından işlenilmekte.");
                Task.Delay(150).Wait();
                return(a);
            }, new ExecutionDataflowBlockOptions()
            {
                MaxDegreeOfParallelism = 3
            });

            broadcastBlock.LinkTo(a1);
            broadcastBlock.LinkTo(a2);

            var joinBlock = new BatchedJoinBlock <int, int>(3);

            a1.LinkTo(joinBlock.Target1);
            a2.LinkTo(joinBlock.Target2);

            var printBlock = new ActionBlock <Tuple <IList <int>, IList <int> > >(a => Console.WriteLine($"Mesaj: [{string.Join(',', a.Item1)}] , [{string.Join(',', a.Item2)}]"));

            joinBlock.LinkTo(printBlock);

            for (int i = 0; i < 10; i++)
            {
                broadcastBlock.SendAsync(i).ContinueWith(a =>
                {
                    if (a.Result)
                    {
                        Console.WriteLine($"{i} mesajı kabul edildi.");
                    }
                    else
                    {
                        Console.WriteLine($"{i} mesajı reddedildi.");
                    }
                });
            }
        }
コード例 #3
0
        public void BasicUsageTest()
        {
            Tuple <IList <int>, IList <int> > result = null;
            var evt = new ManualResetEventSlim(false);

            var actionBlock = new ActionBlock <Tuple <IList <int>, IList <int> > > (r =>
            {
                result = r;
                evt.Set();
            });
            var block = new BatchedJoinBlock <int, int> (2);

            block.LinkTo(actionBlock);

            // both targets once
            Assert.IsTrue(block.Target1.Post(1));

            Assert.IsFalse(evt.Wait(100));
            Assert.IsNull(result);

            Assert.IsTrue(block.Target2.Post(2));

            Assert.IsTrue(evt.Wait(100));

            Assert.IsNotNull(result);
            CollectionAssert.AreEqual(new[] { 1 }, result.Item1);
            CollectionAssert.AreEqual(new[] { 2 }, result.Item2);

            result = null;
            evt.Reset();

            // target 1 twice
            Assert.IsTrue(block.Target1.Post(3));

            Assert.IsFalse(evt.Wait(100));
            Assert.IsNull(result);

            Assert.IsTrue(block.Target1.Post(4));
            Assert.IsTrue(evt.Wait(100));

            Assert.IsNotNull(result);
            CollectionAssert.AreEqual(new[] { 3, 4 }, result.Item1);
            CollectionAssert.IsEmpty(result.Item2);

            result = null;
            evt.Reset();

            // target 2 twice
            Assert.IsTrue(block.Target2.Post(5));

            Assert.IsFalse(evt.Wait(100));
            Assert.IsNull(result);

            Assert.IsTrue(block.Target2.Post(6));
            Assert.IsTrue(evt.Wait(100));

            Assert.IsNotNull(result);
            CollectionAssert.IsEmpty(result.Item1);
            CollectionAssert.AreEqual(new[] { 5, 6 }, result.Item2);
        }
コード例 #4
0
        public void BasicUsageTest()
        {
            Tuple <IList <int>, IList <int>, IList <string> > result = null;
            var evt = new ManualResetEventSlim(false);

            var actionBlock =
                new ActionBlock <Tuple <IList <int>, IList <int>, IList <string> > > (r =>
            {
                result = r;
                evt.Set();
            });
            var block = new BatchedJoinBlock <int, int, string> (3);

            block.LinkTo(actionBlock);

            // all targets once
            Assert.IsTrue(block.Target1.Post(1));
            Assert.IsTrue(block.Target2.Post(2));

            Assert.IsFalse(evt.Wait(100));
            Assert.IsNull(result);

            Assert.IsTrue(block.Target3.Post("foo"));

            Assert.IsTrue(evt.Wait(1000));

            Assert.IsNotNull(result);
            CollectionAssert.AreEqual(new[] { 1 }, result.Item1);
            CollectionAssert.AreEqual(new[] { 2 }, result.Item2);
            CollectionAssert.AreEqual(new[] { "foo" }, result.Item3);
        }
コード例 #5
0
        public async Task BatchedJoinToAction()
        {
            var b = new BatchedJoinBlock <int, int>(1);

            int completedCount = 0;
            var c = new ActionBlock <Tuple <IList <int>, IList <int> > >(i => completedCount++);

            b.LinkTo(c, new DataflowLinkOptions {
                PropagateCompletion = true
            });

            for (int i = 0; i < Iterations; i++)
            {
                if (i % 2 == 0)
                {
                    b.Target1.Post(i);
                }
                else
                {
                    b.Target2.Post(i);
                }
            }
            b.Target1.Complete();
            b.Target2.Complete();

            await c.Completion;

            Assert.Equal(expected: Iterations / b.BatchSize, actual: completedCount);
        }
コード例 #6
0
ファイル: BatchedJoinBlockTest.cs プロジェクト: nlhepler/mono
		public void BasicUsageTest()
		{
			Tuple<IList<int>, IList<int>> result = null;
			var evt = new ManualResetEventSlim (false);

			var actionBlock = new ActionBlock<Tuple<IList<int>, IList<int>>> (r =>
			{
				result = r;
				evt.Set ();
			});
			var block = new BatchedJoinBlock<int, int> (2);

			block.LinkTo (actionBlock);

			// both targets once
			Assert.IsTrue (block.Target1.Post (1));

			Assert.IsFalse(evt.Wait(100));
			Assert.IsNull (result);

			Assert.IsTrue (block.Target2.Post (2));

			Assert.IsTrue (evt.Wait (100));

			Assert.IsNotNull (result);
			CollectionAssert.AreEqual (new[] { 1 }, result.Item1);
			CollectionAssert.AreEqual (new[] { 2 }, result.Item2);

			result = null;
			evt.Reset ();

			// target 1 twice
			Assert.IsTrue (block.Target1.Post (3));

			Assert.IsFalse(evt.Wait(100));
			Assert.IsNull (result);

			Assert.IsTrue (block.Target1.Post (4));
			Assert.IsTrue (evt.Wait (100));

			Assert.IsNotNull (result);
			CollectionAssert.AreEqual (new[] { 3, 4 }, result.Item1);
			CollectionAssert.IsEmpty (result.Item2);

			result = null;
			evt.Reset ();

			// target 2 twice
			Assert.IsTrue (block.Target2.Post (5));

			Assert.IsFalse(evt.Wait(100));
			Assert.IsNull (result);

			Assert.IsTrue (block.Target2.Post (6));
			Assert.IsTrue (evt.Wait (100));

			Assert.IsNotNull (result);
			CollectionAssert.IsEmpty (result.Item1);
			CollectionAssert.AreEqual (new[] { 5, 6 }, result.Item2);
		}
コード例 #7
0
        public async Task TestPrecanceled3()
        {
            var b = new BatchedJoinBlock <int, int, int>(42,
                                                         new GroupingDataflowBlockOptions {
                CancellationToken = new CancellationToken(canceled: true), MaxNumberOfGroups = 1
            });

            Tuple <IList <int>, IList <int>, IList <int> >          ignoredValue;
            IList <Tuple <IList <int>, IList <int>, IList <int> > > ignoredValues;

            Assert.NotNull(b.LinkTo(new ActionBlock <Tuple <IList <int>, IList <int>, IList <int> > >(delegate { })));
            Assert.False(b.Target1.Post(42));
            Assert.False(b.Target2.Post(42));

            foreach (var target in new[] { b.Target1, b.Target2 })
            {
                var t = target.SendAsync(42);
                Assert.True(t.IsCompleted);
                Assert.False(t.Result);
            }

            Assert.False(b.TryReceiveAll(out ignoredValues));
            Assert.False(b.TryReceive(out ignoredValue));
            Assert.Equal(expected: 0, actual: b.OutputCount);
            Assert.NotNull(b.Completion);
            b.Target1.Complete();
            b.Target2.Complete();

            await Assert.ThrowsAnyAsync <OperationCanceledException>(() => b.Completion);
        }
コード例 #8
0
ファイル: Program.cs プロジェクト: lsfera/Tesseract
        // BatchJoinBlocks allow you to optimize on message rate vs. message order.
        // MessageCount is what is batched from all the inputs.
        //
        // The output is difficult to discern but you could have:
        // An empty Batch1, an empty Batch2, or both empty!
        // A full Batch1, a full Batch2, or both full!
        // A full Batch1, a partial/empty Batch2!
        // A partial/empty Batch1, a full Batch2!
        // Both partially filled!
        //
        // This is a fast way to consume data, but you will have to add some boiler plate condtions
        // to your code to handle all the possible scenarios since it is unpredictable in
        // nature.
        private static async Task SimpleDemoAsync()
        {
            Console.WriteLine("BatchJoinBlockDemo has started!");
            var bufferExecutionOptions = new ExecutionDataflowBlockOptions {
                BoundedCapacity = 10
            };
            var transformOptions = new ExecutionDataflowBlockOptions {
                MaxDegreeOfParallelism = 5
            };                                                                                       // add parallelism back
            var options = new DataflowLinkOptions {
                PropagateCompletion = true
            };

            var bufferBlock    = new BufferBlock <string>(bufferExecutionOptions);
            var broadCastBlock = new BroadcastBlock <string>(
                input => input);
            var transform1 = new TransformBlock <string, string>(
                (input) => $"TB1: {input}",
                transformOptions);
            var transform2 = new TransformBlock <string, string>(
                (input) => $"TB2: {input}",
                transformOptions);

            bufferBlock.LinkTo(broadCastBlock, options);
            broadCastBlock.LinkTo(transform1, options);
            broadCastBlock.LinkTo(transform2, options);

            var batchJoinBlock = new BatchedJoinBlock <string, string>(2);

            transform1.LinkTo(batchJoinBlock.Target1, options); // You have to stitch up where the executions are going in your join block.
            transform2.LinkTo(batchJoinBlock.Target2, options);

            var actionBlock = new ActionBlock <Tuple <IList <string>, IList <string> > >(
                (inputs) => Console.WriteLine($"Batch1: {string.Join(", ", inputs.Item1)}\r\nBatch2: {string.Join(", ", inputs.Item2)}\r\n-------"));

            batchJoinBlock.LinkTo(actionBlock, options);

            for (int i = 0; i < 20; i++)
            {
                await bufferBlock
                .SendAsync(ProduceTimeData(i))
                .ConfigureAwait(false);
            }

            bufferBlock.Complete();
            //await bufferBlock.Completion.ConfigureAwait(false);
            //await broadCastBlock.Completion.ConfigureAwait(false);
            //await transform1.Completion.ConfigureAwait(false);
            //await transform2.Completion.ConfigureAwait(false);

            // Because we are using PropagateCompletion = true and the last block is a single ActionBlock,
            // we will wait for all our marbles to reach the finish line with a single line.
            await actionBlock.Completion.ConfigureAwait(false);

            Console.WriteLine("Finished!");
            Console.ReadKey();
        }
コード例 #9
0
        private static void TestBatchedJoinBlock()
        {
            //Func<int, int> DoWork = n =>
            //{
            //    if (n < 0)
            //    {
            //        throw new ArgumentOutOfRangeException();
            //    }
            //    return n;
            //};

            //var batchedJoinBlock = new BatchedJoinBlock<int, Exception>(7);
            //foreach (int i in new int[] { 5, 6, -7, -22, 13, 55, 0 })
            //{
            //    try
            //    {
            //        batchedJoinBlock.Target1.Post(DoWork(i));
            //    }
            //    catch (ArgumentOutOfRangeException ex)
            //    {
            //        batchedJoinBlock.Target2.Post(ex);
            //    }
            //}
            //var res = batchedJoinBlock.Receive();
            //foreach (int n in res.Item1)
            //{
            //    Console.WriteLine(n);
            //}
            //foreach (Exception e in res.Item2)
            //{
            //    Console.WriteLine(e.Message);
            //}

            var bjb = new BatchedJoinBlock <int, string>(3);
            var ab  = new ActionBlock <Tuple <IList <int>, IList <string> > >(i =>
            {
                Console.WriteLine("------------------------------------");
                foreach (int m in i.Item1)
                {
                    Console.WriteLine(m);
                }
                foreach (string s in i.Item2)
                {
                    Console.WriteLine(s);
                }
            });

            bjb.LinkTo(ab);
            for (int i = 0; i < 5; i++)
            {
                bjb.Target1.Post(i);
            }
            for (int i = 5; i > 0; i--)
            {
                bjb.Target2.Post(i.ToString());
            }
        }
コード例 #10
0
        public async Task SimpleBatchedJoin()
        {
            var block = new BroadcastBlock <int>(a => a);

            Random random = new Random();

            var action1 = new TransformBlock <int, int>(a =>
            {
                Console.WriteLine($"Processed by consumer 1 : {a}");
                Task.Delay(random.Next(0, 1000)).Wait();
                return(a * -1);
            }, new ExecutionDataflowBlockOptions());

            var action2 = new TransformBlock <int, int>(a =>
            {
                Console.WriteLine($"Processed by consumer 2 : {a}");
                Task.Delay(random.Next(0, 1000)).Wait();
                return(a);
            }, new ExecutionDataflowBlockOptions());

            block.LinkTo(action1);
            block.LinkTo(action2);

            var joinBlock = new BatchedJoinBlock <int, int>(3);

            action1.LinkTo(joinBlock.Target1);
            action2.LinkTo(joinBlock.Target2);

            var printBlock = new ActionBlock <Tuple <IList <int>, IList <int> > >(a =>
            {
                Console.WriteLine($"Processed: [{string.Join(",",a.Item1)}],[{string.Join(",", a.Item2)}]");
            });

            joinBlock.LinkTo(printBlock);

            for (int i = 0; i < 10; i++)
            {
                await block.SendAsync(i);

                Console.WriteLine($"Message {i} was sended");
            }

            block.Complete();

            await block.Completion;

            action2.Complete();
            action1.Complete();

            await action2.Completion;
            await action1.Completion;

            Console.WriteLine("Done!");
        }
コード例 #11
0
        static void Main(string[] args)
        {
            var broadcastBlock = new BroadcastBlock <int>(a => a);

            var a1 = new TransformBlock <int, int>(n => {
                Console.WriteLine($"Message {n} received by Consumer 1");
                Task.Delay(n % 2 == 0 ? 300 : 100).Wait(); // Join block will still pair them correctly
                return(n * -1);
            }, new ExecutionDataflowBlockOptions {
                MaxDegreeOfParallelism = 3
            });

            var a2 = new TransformBlock <int, int>(n => {
                Console.WriteLine($"Message {n} received by Consumer 2");
                Task.Delay(n % 2 == 0 ? 100 : 300).Wait(); // Join block will still pair them correctly
                return(n);
            }, new ExecutionDataflowBlockOptions {
                MaxDegreeOfParallelism = 3
            });

            broadcastBlock.LinkTo(a1); // Messages will be proposed in this order
            broadcastBlock.LinkTo(a2);

            var batchedJoinBlock = new BatchedJoinBlock <int, int>(3);

            a1.LinkTo(batchedJoinBlock.Target1);
            a2.LinkTo(batchedJoinBlock.Target2);

            var printBlock = new ActionBlock <Tuple <IList <int>, IList <int> > >(
                a => Console.WriteLine($"Message {string.Join(",", a.Item1)} : {string.Join(",", a.Item2)}")
                );

            batchedJoinBlock.LinkTo(printBlock);

            for (int i = 0; i < 10; i++)
            {
                broadcastBlock.SendAsync(i) // List Post, if receivers are not ready then they will be ignored, there is no retry
                .ContinueWith(a =>
                {
                    if (a.Result)
                    {
                        Console.WriteLine($"Accepted {i}");
                    }
                    else
                    {
                        Console.WriteLine($"Rejected {i}");
                    }
                });
            }

            Console.WriteLine("Finished!");
            Console.ReadKey();
        }
コード例 #12
0
 public static void TestSync()
 {
     bjb.LinkTo(ab);
     for (int i = 0; i < 5; i++)
     {
         bjb.Target1.Post(i);
     }
     for (int i = 5; i > 0; i--)
     {
         bjb.Target2.Post(i.ToString());
     }
     Console.WriteLine("Finished post");
 }
コード例 #13
0
    public SynchronizedJoinBlock(Func <T1, T2, int> compareFunction)
    {
        _compareFunction = compareFunction
                           ?? throw new ArgumentNullException(nameof(compareFunction));
        _batchedJoinBlock = new BatchedJoinBlock <Tuple <T1, T2>, Tuple <T1, T2> >(1);
        _target1Messages  = new Queue <T1>();
        _target2Messages  = new Queue <T2>();
        var syncObject = new object();
        Func <ICollection <Tuple <T1, T2> > > getMessagesFunction = () =>
        {
            lock (syncObject)
            {
                if (_target1Messages.Count > 0 && _target2Messages.Count > 0)
                {
                    return(GetMessagesRecursive(_target1Messages.Peek(), _target2Messages.Peek()).ToArray());
                }
                else
                {
                    return(new Tuple <T1, T2> [0]);
                }
            }
        };

        _target1 = new TransformManyBlock <T1, Tuple <T1, T2> >((element) =>
        {
            _target1Messages.Enqueue(element);
            return(getMessagesFunction());
        });
        _target1.LinkTo(_batchedJoinBlock.Target1, new DataflowLinkOptions()
        {
            PropagateCompletion = true
        });
        _target2 = new TransformManyBlock <T2, Tuple <T1, T2> >((element) =>
        {
            _target2Messages.Enqueue(element);
            return(getMessagesFunction());
        });
        _target2.LinkTo(_batchedJoinBlock.Target2, new DataflowLinkOptions()
        {
            PropagateCompletion = true
        });
        _transformManyBlock = new TransformManyBlock <Tuple <IList <Tuple <T1, T2> >, IList <Tuple <T1, T2> > >, Tuple <T1, T2> >(
            element => element.Item1.Concat(element.Item2)
            );
        _batchedJoinBlock.LinkTo(_transformManyBlock, new DataflowLinkOptions()
        {
            PropagateCompletion = true
        });
    }
コード例 #14
0
        public IDictionary <string, string[]> BatchedJoinBlockUsage(int numberOfIteration, int batchsize)
        {
            Console.WriteLine($"Inside {nameof(TplDataflow3GroupingBlocksController)} - {nameof(BatchedJoinBlockUsage)}");

            var ouputCollection = new Dictionary <string, string[]>();

            Functions.ClearCounterForBatchedJoinBlockUsage();

            // Create the members of the pipeline.
            var broadCastBlock             = new BroadcastBlock <int>(i => i);
            var transformBlockDoNothing    = new TransformBlock <int, int>(i => i);
            var transformBlockSquare       = new TransformBlock <int, int>(i => i * i);
            var transformBlockMultipleByPi = new TransformBlock <int, double>(i => i * Math.PI);
            var batchedJoinBlock           = new BatchedJoinBlock <int, int, double>(batchsize);
            var processorBlock             = new ActionBlock <Tuple <IList <int>, IList <int>, IList <double> > >(tuple =>
                                                                                                                  Functions.FormatTupleForTheOuputCollection(ouputCollection, tuple)
                                                                                                                  );

            // Connect the dataflow blocks to form a pipeline.
            broadCastBlock.LinkTo(transformBlockDoNothing, DataflowOptions.LinkOptions);
            broadCastBlock.LinkTo(transformBlockSquare, DataflowOptions.LinkOptions);
            broadCastBlock.LinkTo(transformBlockMultipleByPi, DataflowOptions.LinkOptions);
            transformBlockDoNothing.LinkTo(batchedJoinBlock.Target1);
            transformBlockSquare.LinkTo(batchedJoinBlock.Target2);
            transformBlockMultipleByPi.LinkTo(batchedJoinBlock.Target3);
            batchedJoinBlock.LinkTo(processorBlock, DataflowOptions.LinkOptions);

            // Start BatchedJoinBlockUsage pipeline with the input values.
            for (var i = 0; i < numberOfIteration; i++)
            {
                broadCastBlock.Post(i);
            }

            // Mark the head of the pipeline as complete.
            broadCastBlock.Complete();

            // Wait for the last block in the pipeline to process all messages.
            Task.WhenAll(transformBlockDoNothing.Completion,
                         transformBlockSquare.Completion,
                         transformBlockMultipleByPi.Completion)
            .ContinueWith(_ => batchedJoinBlock.Complete());
            processorBlock.Completion.Wait();

            return(ouputCollection);
        }
コード例 #15
0
ファイル: Program.cs プロジェクト: nhonduyen/parallel
        public static void GetRandomEmployee(int batchSize, int count)
        {
            Employee em = new Employee();
            var      selectEmployees = new BatchedJoinBlock <Employee, Exception>(batchSize);

            int totalException = 0;

            var printEmployees = new ActionBlock <Tuple <IList <Employee>, IList <Exception> > >(data =>
            {
                Console.WriteLine("Recieve a batch");
                foreach (var emp in data.Item1)
                {
                    Console.WriteLine("{0} {1} ID={2}", emp.FirstName, emp.LastName, emp.EmployeeId);
                }
                Console.WriteLine("There was {0} errors in this batch", data.Item2.Count);
                totalException += data.Item2.Count;
            });

            selectEmployees.LinkTo(printEmployees);
            selectEmployees.Completion.ContinueWith(delegate { printEmployees.Complete(); });
            Console.WriteLine("Select random employee");
            for (int i = 0; i < 10; i++)
            {
                try
                {
                    Employee ranEmp = em.GetRandomEmployee().FirstOrDefault();
                    selectEmployees.Target1.Post(ranEmp);
                }
                catch (NullReferenceException ex)
                {
                    Console.WriteLine("Null Exception {0}", ex.InnerException);
                    selectEmployees.Target2.Post(ex);
                }
            }
            selectEmployees.Complete();
            printEmployees.Completion.Wait();
            Console.WriteLine("Finished get employee. There was {0} error", totalException);
        }
コード例 #16
0
        // Displays information about several random employees to the console.
        static void GetRandomEmployees(string connectionString, int batchSize, int count)
        {
            // Create a BatchedJoinBlock<Employee, Exception> object that holds
            // both employee and exception data.
            BatchedJoinBlock <Employee, Exception> selectEmployees = new BatchedJoinBlock <Employee, Exception>(batchSize);

            // Holds the total number of exceptions that occurred.
            int totalErrors = 0;

            // Create an action block that prints employee and error information
            // to the console.
            ActionBlock <Tuple <IList <Employee>, IList <Exception> > > printEmployees =
                new ActionBlock <Tuple <IList <Employee>, IList <Exception> > >(data =>
            {
                // Print information about the employees in this batch.
                Console.WriteLine("Received a batch...");
                foreach (Employee e in data.Item1)
                {
                    Console.WriteLine("Last={0} First={1} ID={2}",
                                      e.FirstName, e.LastName, e.EmployeeID);
                }

                // Print the error count for this batch.
                Console.WriteLine("There were {0} errors in this batch...",
                                  data.Item2.Count);

                // Update total error count.
                totalErrors += data.Item2.Count;
            });

            // Link the batched join block to the action block.
            selectEmployees.LinkTo(printEmployees);

            // When the batched join block completes, set the action block also to complete.
            selectEmployees.Completion.ContinueWith(delegate { printEmployees.Complete(); });

            // Try to retrieve the ID for several random employees.
            Console.WriteLine("Selecting random entries from Employees table...");
            for (int i = 0; i < count; i++)
            {
                try
                {
                    // Create a random employee.
                    Employee e = Employee.Random();

                    // Try to retrieve the ID for the employee from the database.
                    e.EmployeeID = DatabaseUtilities.GetEmployeeID(e.LastName, e.FirstName, connectionString);

                    // Post the Employee object to the Employee target of
                    // the batched join block.
                    selectEmployees.Target1.Post(e);
                }
                catch (NullReferenceException e)
                {
                    // GetEmployeeID throws NullReferenceException when there is
                    // no such employee with the given name. When this happens,
                    // post the Exception object to the Exception target of
                    // the batched join block.
                    selectEmployees.Target2.Post(e);
                }
            }

            // Set the batched join block to the completed state and wait for
            // all retrieval operations to complete.
            selectEmployees.Complete();
            printEmployees.Completion.Wait();

            // Print the total error count.
            Console.WriteLine("Finished. There were {0} total errors.", totalErrors);
        }
コード例 #17
0
        public void RunBatchedJoinBlockConformanceTests()
        {
            // Test Post/Receive single block
            var block = new BatchedJoinBlock<int, int>(2);
            int iter = 10;
            for (int i = 0; i < iter; i++)
            {
                block.Target1.Post(i);
                block.Target2.Post(i);
                if (i % block.BatchSize == 0)
                {
                    var msg = block.Receive();
                    Assert.False(msg.Item1.Count != msg.Item2.Count, "BatchedJoinBlock Post/Receive failed, returned arrays of differnet length");
                    for (int j = 0; j < msg.Item1.Count; j++)
                    {
                        if (msg.Item1[j] != msg.Item2[j])
                        {
                            Assert.False(true, "BatchedJoinBlock Post/Receive failed, returned arrys items are different");
                        }
                    }
                }
            }

            // Test PostAll then Receive single block
            block = new BatchedJoinBlock<int, int>(2);
            for (int i = 0; i < iter; i++)
            {
                block.Target1.Post(i);
                block.Target2.Post(i);
            }

            Assert.False(block.OutputCount != iter, string.Format("BatchedJoinBlock Post failed, expected, incorrect OutputCount. Expected {0} actual {1}", iter, block.OutputCount));

            for (int i = 0; i < block.OutputCount; i++)
            {
                var msg = block.Receive();
                if (msg.Item1.Count != msg.Item2.Count)
                {
                    Assert.False(true, "BatchedJoinBlock PostAll then Receive failed, returned arrays of differnet length");
                }
                for (int j = 0; j < msg.Item1.Count; j++)
                {
                    if (msg.Item1[j] != msg.Item2[j])
                    {
                        Assert.False(true, "BatchedJoinBlock PostAll then Receive failed, returned arrys items are different");
                    }
                }
            }

            //Test one target Post < patchSize msg with TryReceive
            block = new BatchedJoinBlock<int, int>(2);
            block.Target1.Post(0);
            Tuple<IList<int>, IList<int>> result;
            if (block.TryReceive(out result))
            {
                Assert.False(true, "BatchedJoinBlock.TryReceive failed, returned true and the number of messages is less than the batch size");
            }
            if (block.OutputCount > 0)
            {
                Assert.False(true, "BatchedJoinBlock.OutputCount failed, returned count > 0 and only one target posted a message");
            }

            // Test handling of stragglers at end of block's life
            block = new BatchedJoinBlock<int, int>(2);
            for (int i = 0; i < 10; i++)
            {
                block.Target1.Post(i);
                block.Target2.Post(i);
            }
            block.Target1.Post(10);
            block.Target1.Complete();
            block.Target2.Complete();
            if (block.OutputCount != 11)
            {
                Assert.False(true, "BatchedJoinBlock last batch not generated correctly");
            }

            for (int i = 0; i < 10; i++) block.Receive();
            var lastResult = block.Receive();
            if (lastResult.Item1.Count != 1 || lastResult.Item2.Count != 0)
            {
                Assert.False(true, "BatchedJoinBlock last batch contains incorrect data");
            }

            // Test BatchedJoinBlock`2 using a precanceled token
            {
                var localPassed = true;
                try
                {
                    var cts = new CancellationTokenSource();
                    cts.Cancel();
                    var dbo = new GroupingDataflowBlockOptions { CancellationToken = cts.Token, MaxNumberOfGroups = 1 };
                    var bjb = new BatchedJoinBlock<int, int>(42, dbo);

                    Tuple<IList<int>, IList<int>> ignoredValue;
                    IList<Tuple<IList<int>, IList<int>>> ignoredValues;
                    localPassed &= bjb.LinkTo(new ActionBlock<Tuple<IList<int>, IList<int>>>(delegate { })) != null;
                    localPassed &= bjb.Target1.Post(42) == false;
                    localPassed &= bjb.Target2.Post(42) == false;
                    localPassed &= bjb.Target1.SendAsync(42).Result == false;
                    localPassed &= bjb.Target2.SendAsync(42).Result == false;
                    localPassed &= bjb.TryReceiveAll(out ignoredValues) == false;
                    localPassed &= bjb.TryReceive(out ignoredValue) == false;
                    localPassed &= bjb.OutputCount == 0;
                    localPassed &= bjb.Completion != null;
                    bjb.Target1.Complete();
                    bjb.Target2.Complete();
                }
                catch (Exception)
                {
                    localPassed = false;
                }

                Assert.True(localPassed, "Precanceled tokens don't work correctly on BJB`2");
            }

            // Test BatchedJoinBlock`3 using a precanceled token
            {
                var localPassed = true;
                try
                {
                    var cts = new CancellationTokenSource();
                    cts.Cancel();
                    var dbo = new GroupingDataflowBlockOptions { CancellationToken = cts.Token, MaxNumberOfGroups = 1 };
                    var bjb = new BatchedJoinBlock<int, int, int>(42, dbo);

                    Tuple<IList<int>, IList<int>, IList<int>> ignoredValue;
                    IList<Tuple<IList<int>, IList<int>, IList<int>>> ignoredValues;
                    localPassed &= bjb.LinkTo(new ActionBlock<Tuple<IList<int>, IList<int>, IList<int>>>(delegate { })) != null;
                    localPassed &= bjb.Target1.Post(42) == false;
                    localPassed &= bjb.Target2.Post(42) == false;
                    localPassed &= bjb.Target3.Post(42) == false;
                    localPassed &= bjb.Target1.SendAsync(42).Result == false;
                    localPassed &= bjb.Target2.SendAsync(42).Result == false;
                    localPassed &= bjb.Target3.SendAsync(42).Result == false;
                    localPassed &= bjb.TryReceiveAll(out ignoredValues) == false;
                    localPassed &= bjb.TryReceive(out ignoredValue) == false;
                    localPassed &= bjb.OutputCount == 0;
                    localPassed &= bjb.Completion != null;
                    bjb.Target1.Complete();
                    bjb.Target2.Complete();
                    bjb.Target3.Complete();
                }
                catch (Exception)
                {
                    localPassed = false;
                }

                Assert.True(localPassed, "Precanceled tokens don't work correctly on BJB`3");
            }

            // Test BatchedJoinBlock`2 completion through all targets
            {
                var localPassed = true;
                var batchedJoin = new BatchedJoinBlock<int, int>(99);
                var terminator = new ActionBlock<Tuple<IList<int>, IList<int>>>(x => { });
                batchedJoin.LinkTo(terminator);
                batchedJoin.Target1.Post(1);
                batchedJoin.Target1.Complete();
                batchedJoin.Target2.Complete();
                localPassed = batchedJoin.Completion.Wait(2000);

                Assert.True(localPassed, string.Format("BatchedJoinBlock`2 completed through targets - {0}", localPassed ? "Passed" : "FAILED"));
            }

            // Test BatchedJoinBlock`3 completion through all targets
            {
                var localPassed = true;
                var batchedJoin = new BatchedJoinBlock<int, int, int>(99);
                var terminator = new ActionBlock<Tuple<IList<int>, IList<int>, IList<int>>>(x => { });
                batchedJoin.LinkTo(terminator);
                batchedJoin.Target1.Post(1);
                batchedJoin.Target1.Complete();
                batchedJoin.Target2.Complete();
                batchedJoin.Target3.Complete();
                localPassed = batchedJoin.Completion.Wait(2000);

                Assert.True(localPassed, string.Format("BatchedJoinBlock`3 completed through targets - {0}", localPassed ? "Passed" : "FAILED"));
            }

            // Test BatchedJoinBlock`2 completion through block
            {
                var localPassed = true;
                var batchedJoin = new BatchedJoinBlock<int, int>(99);
                var terminator = new ActionBlock<Tuple<IList<int>, IList<int>>>(x => { });
                batchedJoin.LinkTo(terminator);
                batchedJoin.Target1.Post(1);
                batchedJoin.Complete();
                localPassed = batchedJoin.Completion.Wait(2000);

                Assert.True(localPassed, string.Format("BatchedJoinBlock`2 completed through block - {0}", localPassed ? "Passed" : "FAILED"));
            }

            // Test BatchedJoinBlock`3 completion through block
            {
                var localPassed = true;
                var batchedJoin = new BatchedJoinBlock<int, int, int>(99);
                var terminator = new ActionBlock<Tuple<IList<int>, IList<int>, IList<int>>>(x => { });
                batchedJoin.LinkTo(terminator);
                batchedJoin.Target1.Post(1);
                batchedJoin.Complete();
                localPassed = batchedJoin.Completion.Wait(2000);

                Assert.True(localPassed, string.Format("BatchedJoinBlock`3 completed through block - {0}", localPassed ? "Passed" : "FAILED"));
            }
        }
コード例 #18
0
        public void Test()
        {
            var action = new ActionBlock <int[]>(x => { }, new ExecutionDataflowBlockOptions {
            });
            var batch  = new BatchBlock <int>(10, new GroupingDataflowBlockOptions {
            });

            using var likBA = batch.LinkTo(action, new DataflowLinkOptions { }, x => x[0] > 1); //actionBlock gets 10 elements
            batch.TriggerBatch();                                                               //for leftover elements

            var batchJoined = new BatchedJoinBlock <int[], string>(10, new GroupingDataflowBlockOptions {
            });

            batch.LinkTo(batchJoined.Target1, new DataflowLinkOptions {
            }, ints => ints[0] > 0);
            var action2 = new ActionBlock <Tuple <IList <int[]>, IList <string> > >(x => { });

            using var linkBJA = batchJoined.LinkTo(action2, new DataflowLinkOptions { }, x => x.Item1.Count == x.Item2.Count);//it's 10 total so 7-3 or 0-10 will propagate

            var broadcast = new BroadcastBlock <int>(cloningFunction: x => x, new DataflowBlockOptions {
            });
            var action3   = new ActionBlock <int>(x => { });
            var action4   = new ActionBlock <int>(x => { });

            broadcast.LinkTo(action3, new DataflowLinkOptions {
            }, x => x > 0);
            broadcast.LinkTo(action4, new DataflowLinkOptions {
            }, x => x > 0);                                                    //both will gete same elements

            var buffer  = new BufferBlock <int>(new DataflowBlockOptions {
            });
            var action5 = new ActionBlock <int>(x => { });

            buffer.LinkTo(action5, new DataflowLinkOptions {
            }, x => x == 0);

            var buffer1 = new BufferBlock <int>();
            var join    = new JoinBlock <int, string>(new GroupingDataflowBlockOptions {
            });

            buffer1.LinkTo(join.Target1);
            var action6 = new ActionBlock <Tuple <int, string> >(tlp => { });

            join.LinkTo(action6);

            var transform = new TransformBlock <int, string>(x => x.ToString(), new ExecutionDataflowBlockOptions {
            });
            var action7   = new ActionBlock <string>(str => { });

            transform.LinkTo(action7);

            var transformMany = new TransformManyBlock <int, string>(
                x => Enumerable.Range(0, x).Select(i => i.ToString()));//one recived to many output
            var action8 = new ActionBlock <string>(str => { });

            var writeOnce = new WriteOnceBlock <int>(cloningFunction: x => x, new DataflowBlockOptions {
            });                                                                                            // it gets and stores 1 element but gives clones to linked blocks?
            var action9   = new ActionBlock <int>(x => { });

            writeOnce.LinkTo(action9);

            var bufferC1  = new BufferBlock <int>();
            var bufferC2  = new BufferBlock <string>();
            var actionIdx = DataflowBlock.Choose <int, string>(
                bufferC1, x => Console.WriteLine(x + 1),
                bufferC2, str => Console.WriteLine(str + ""));

            var actionE1   = new ActionBlock <int>(x => { });
            var bufferE1   = new BufferBlock <string>();
            var propagator = DataflowBlock.Encapsulate <int, string>(actionE1, bufferE1);

            var scheduler  = new ConcurrentExclusiveSchedulerPair(TaskScheduler.Default, Environment.ProcessorCount, int.MaxValue);
            var concurrent = scheduler.ConcurrentScheduler;
            var exclusive  = scheduler.ExclusiveScheduler;
        }
コード例 #19
0
        private static async Task Main(string[] args)
        {
            var bufferBlock = new BroadcastBlock <int>(a => a);

            var a1 = new TransformBlock <int, int>(a =>
            {
                Console.WriteLine($"Message {a} was processed by Consumer 1");
                if (a % 2 == 0)
                {
                    Task.Delay(300).Wait();
                }
                else
                {
                    Task.Delay(50).Wait();
                }
                return(a * -1);
            }, new ExecutionDataflowBlockOptions {
                MaxDegreeOfParallelism = 3
            }
                                                   );

            var a2 = new TransformBlock <int, int>(a =>
            {
                Console.WriteLine($"Message {a} was processed by Consumer 2");
                if (a % 2 == 0)
                {
                    Task.Delay(50).Wait();
                }
                else
                {
                    Task.Delay(300).Wait();
                }
                return(a);
            }
                                                   , new ExecutionDataflowBlockOptions {
                MaxDegreeOfParallelism = 3
            }
                                                   );

            bufferBlock.LinkTo(a1);
            bufferBlock.LinkTo(a2);

            var joinBlock = new BatchedJoinBlock <int, int>(3);

            a1.LinkTo(joinBlock.Target1);
            a2.LinkTo(joinBlock.Target2);

            var finalBlock = new ActionBlock <Tuple <IList <int>, IList <int> > >(a =>
            {
                Console.WriteLine($"Message {a.Item1},{a.Item2} was processed by all consumers. Total was [A=={string.Join(",", a.Item1)}:::::B=={string.Join(",", a.Item2)}] ");
            });

            joinBlock.LinkTo(finalBlock);

            for (var i = 0; i < 10; i++)
            {
                await bufferBlock.SendAsync(i);
            }

            Console.WriteLine("Finished!");
            Console.ReadKey();
        }
コード例 #20
0
        static void Main(string[] args)
        {
            var broadcastBlock = new BroadcastBlock <int>(a => a, new DataflowBlockOptions()
            {
                BoundedCapacity = 1
            });

            var a1 = new TransformBlock <int, int>(
                a =>
            {
                Console.WriteLine($"Message {a} was processed by consumer 1");
                if (a % 2 == 0)
                {
                    Task.Delay(300).Wait();
                }
                else
                {
                    Task.Delay(50).Wait();
                }
                return(a * -1);
            }, new ExecutionDataflowBlockOptions()
            {
                MaxDegreeOfParallelism = 3
            });

            var a2 = new TransformBlock <int, int>(
                a =>
            {
                Console.WriteLine($"Message {a} was processed by consumer 2");
                if (a % 2 != 0)
                {
                    Task.Delay(300).Wait();
                }
                else
                {
                    Task.Delay(50).Wait();
                }
                return(a);
            }, new ExecutionDataflowBlockOptions()
            {
                MaxDegreeOfParallelism = 3
            });

            broadcastBlock.LinkTo(a1);
            broadcastBlock.LinkTo(a2);

            var joinblock = new BatchedJoinBlock <int, int>(3);

            a1.LinkTo(joinblock.Target1);
            a2.LinkTo(joinblock.Target2);

            var printBlock = new ActionBlock <Tuple <IList <int>, IList <int> > >(
                a => Console.WriteLine($"Message [{string.Join(",", a.Item1)}]" +
                                       $",[{string.Join(",", a.Item2)}]"));

            joinblock.LinkTo(printBlock);

            for (int i = 0; i < 10; i++)
            {
                var i1 = i;
                broadcastBlock.SendAsync(i)
                .ContinueWith(a =>
                {
                    Console.WriteLine(a.Result ? $"Messgae {i1} was accepted" : $"Messgae {i1} was rejected");
                });
            }

            Console.WriteLine("done");
            Console.ReadLine();
        }
コード例 #21
0
        public async Task TestPrecanceled3()
        {
            var b = new BatchedJoinBlock<int, int, int>(42,
                new GroupingDataflowBlockOptions { CancellationToken = new CancellationToken(canceled: true), MaxNumberOfGroups = 1 });

            Tuple<IList<int>, IList<int>, IList<int>> ignoredValue;
            IList<Tuple<IList<int>, IList<int>, IList<int>>> ignoredValues;

            Assert.NotNull(b.LinkTo(new ActionBlock<Tuple<IList<int>, IList<int>, IList<int>>>(delegate { })));
            Assert.False(b.Target1.Post(42));
            Assert.False(b.Target2.Post(42));

            foreach (var target in new[] { b.Target1, b.Target2 })
            {
                var t = target.SendAsync(42);
                Assert.True(t.IsCompleted);
                Assert.False(t.Result);
            }

            Assert.False(b.TryReceiveAll(out ignoredValues));
            Assert.False(b.TryReceive(out ignoredValue));
            Assert.Equal(expected: 0, actual: b.OutputCount);
            Assert.NotNull(b.Completion);
            b.Target1.Complete();
            b.Target2.Complete();

            await Assert.ThrowsAnyAsync<OperationCanceledException>(() => b.Completion);
        }
コード例 #22
0
        public async Task BatchedJoinToAction()
        {
            var b = new BatchedJoinBlock<int, int>(1);

            int completedCount = 0;
            var c = new ActionBlock<Tuple<IList<int>, IList<int>>>(i => completedCount++);
            b.LinkTo(c, new DataflowLinkOptions { PropagateCompletion = true });

            for (int i = 0; i < Iterations; i++)
            {
                if (i % 2 == 0) b.Target1.Post(i);
                else b.Target2.Post(i);
            }
            b.Target1.Complete();
            b.Target2.Complete();

            await c.Completion;
            Assert.Equal(expected: Iterations / b.BatchSize, actual: completedCount);
        }
コード例 #23
0
        public void RunBatchedJoinBlockConformanceTests()
        {
            // Test Post/Receive single block
            var block = new BatchedJoinBlock <int, int>(2);
            int iter  = 10;

            for (int i = 0; i < iter; i++)
            {
                block.Target1.Post(i);
                block.Target2.Post(i);
                if (i % block.BatchSize == 0)
                {
                    var msg = block.Receive();
                    Assert.False(msg.Item1.Count != msg.Item2.Count, "BatchedJoinBlock Post/Receive failed, returned arrays of differnet length");
                    for (int j = 0; j < msg.Item1.Count; j++)
                    {
                        if (msg.Item1[j] != msg.Item2[j])
                        {
                            Assert.False(true, "BatchedJoinBlock Post/Receive failed, returned arrys items are different");
                        }
                    }
                }
            }

            // Test PostAll then Receive single block
            block = new BatchedJoinBlock <int, int>(2);
            for (int i = 0; i < iter; i++)
            {
                block.Target1.Post(i);
                block.Target2.Post(i);
            }

            Assert.False(block.OutputCount != iter, string.Format("BatchedJoinBlock Post failed, expected, incorrect OutputCount. Expected {0} actual {1}", iter, block.OutputCount));

            for (int i = 0; i < block.OutputCount; i++)
            {
                var msg = block.Receive();
                if (msg.Item1.Count != msg.Item2.Count)
                {
                    Assert.False(true, "BatchedJoinBlock PostAll then Receive failed, returned arrays of differnet length");
                }
                for (int j = 0; j < msg.Item1.Count; j++)
                {
                    if (msg.Item1[j] != msg.Item2[j])
                    {
                        Assert.False(true, "BatchedJoinBlock PostAll then Receive failed, returned arrys items are different");
                    }
                }
            }

            //Test one target Post < patchSize msg with TryReceive
            block = new BatchedJoinBlock <int, int>(2);
            block.Target1.Post(0);
            Tuple <IList <int>, IList <int> > result;

            if (block.TryReceive(out result))
            {
                Assert.False(true, "BatchedJoinBlock.TryReceive failed, returned true and the number of messages is less than the batch size");
            }
            if (block.OutputCount > 0)
            {
                Assert.False(true, "BatchedJoinBlock.OutputCount failed, returned count > 0 and only one target posted a message");
            }

            // Test handling of stragglers at end of block's life
            block = new BatchedJoinBlock <int, int>(2);
            for (int i = 0; i < 10; i++)
            {
                block.Target1.Post(i);
                block.Target2.Post(i);
            }
            block.Target1.Post(10);
            block.Target1.Complete();
            block.Target2.Complete();
            if (block.OutputCount != 11)
            {
                Assert.False(true, "BatchedJoinBlock last batch not generated correctly");
            }

            for (int i = 0; i < 10; i++)
            {
                block.Receive();
            }
            var lastResult = block.Receive();

            if (lastResult.Item1.Count != 1 || lastResult.Item2.Count != 0)
            {
                Assert.False(true, "BatchedJoinBlock last batch contains incorrect data");
            }

            // Test BatchedJoinBlock`2 using a precanceled token
            {
                var localPassed = true;
                try
                {
                    var cts = new CancellationTokenSource();
                    cts.Cancel();
                    var dbo = new GroupingDataflowBlockOptions {
                        CancellationToken = cts.Token, MaxNumberOfGroups = 1
                    };
                    var bjb = new BatchedJoinBlock <int, int>(42, dbo);

                    Tuple <IList <int>, IList <int> >          ignoredValue;
                    IList <Tuple <IList <int>, IList <int> > > ignoredValues;
                    localPassed &= bjb.LinkTo(new ActionBlock <Tuple <IList <int>, IList <int> > >(delegate { })) != null;
                    localPassed &= bjb.Target1.Post(42) == false;
                    localPassed &= bjb.Target2.Post(42) == false;
                    localPassed &= bjb.Target1.SendAsync(42).Result == false;
                    localPassed &= bjb.Target2.SendAsync(42).Result == false;
                    localPassed &= bjb.TryReceiveAll(out ignoredValues) == false;
                    localPassed &= bjb.TryReceive(out ignoredValue) == false;
                    localPassed &= bjb.OutputCount == 0;
                    localPassed &= bjb.Completion != null;
                    bjb.Target1.Complete();
                    bjb.Target2.Complete();
                }
                catch (Exception)
                {
                    localPassed = false;
                }

                Assert.True(localPassed, "Precanceled tokens don't work correctly on BJB`2");
            }

            // Test BatchedJoinBlock`3 using a precanceled token
            {
                var localPassed = true;
                try
                {
                    var cts = new CancellationTokenSource();
                    cts.Cancel();
                    var dbo = new GroupingDataflowBlockOptions {
                        CancellationToken = cts.Token, MaxNumberOfGroups = 1
                    };
                    var bjb = new BatchedJoinBlock <int, int, int>(42, dbo);

                    Tuple <IList <int>, IList <int>, IList <int> >          ignoredValue;
                    IList <Tuple <IList <int>, IList <int>, IList <int> > > ignoredValues;
                    localPassed &= bjb.LinkTo(new ActionBlock <Tuple <IList <int>, IList <int>, IList <int> > >(delegate { })) != null;
                    localPassed &= bjb.Target1.Post(42) == false;
                    localPassed &= bjb.Target2.Post(42) == false;
                    localPassed &= bjb.Target3.Post(42) == false;
                    localPassed &= bjb.Target1.SendAsync(42).Result == false;
                    localPassed &= bjb.Target2.SendAsync(42).Result == false;
                    localPassed &= bjb.Target3.SendAsync(42).Result == false;
                    localPassed &= bjb.TryReceiveAll(out ignoredValues) == false;
                    localPassed &= bjb.TryReceive(out ignoredValue) == false;
                    localPassed &= bjb.OutputCount == 0;
                    localPassed &= bjb.Completion != null;
                    bjb.Target1.Complete();
                    bjb.Target2.Complete();
                    bjb.Target3.Complete();
                }
                catch (Exception)
                {
                    localPassed = false;
                }

                Assert.True(localPassed, "Precanceled tokens don't work correctly on BJB`3");
            }

            // Test BatchedJoinBlock`2 completion through all targets
            {
                var localPassed = true;
                var batchedJoin = new BatchedJoinBlock <int, int>(99);
                var terminator  = new ActionBlock <Tuple <IList <int>, IList <int> > >(x => { });
                batchedJoin.LinkTo(terminator);
                batchedJoin.Target1.Post(1);
                batchedJoin.Target1.Complete();
                batchedJoin.Target2.Complete();
                localPassed = batchedJoin.Completion.Wait(2000);

                Assert.True(localPassed, string.Format("BatchedJoinBlock`2 completed through targets - {0}", localPassed ? "Passed" : "FAILED"));
            }

            // Test BatchedJoinBlock`3 completion through all targets
            {
                var localPassed = true;
                var batchedJoin = new BatchedJoinBlock <int, int, int>(99);
                var terminator  = new ActionBlock <Tuple <IList <int>, IList <int>, IList <int> > >(x => { });
                batchedJoin.LinkTo(terminator);
                batchedJoin.Target1.Post(1);
                batchedJoin.Target1.Complete();
                batchedJoin.Target2.Complete();
                batchedJoin.Target3.Complete();
                localPassed = batchedJoin.Completion.Wait(2000);

                Assert.True(localPassed, string.Format("BatchedJoinBlock`3 completed through targets - {0}", localPassed ? "Passed" : "FAILED"));
            }

            // Test BatchedJoinBlock`2 completion through block
            {
                var localPassed = true;
                var batchedJoin = new BatchedJoinBlock <int, int>(99);
                var terminator  = new ActionBlock <Tuple <IList <int>, IList <int> > >(x => { });
                batchedJoin.LinkTo(terminator);
                batchedJoin.Target1.Post(1);
                batchedJoin.Complete();
                localPassed = batchedJoin.Completion.Wait(2000);

                Assert.True(localPassed, string.Format("BatchedJoinBlock`2 completed through block - {0}", localPassed ? "Passed" : "FAILED"));
            }

            // Test BatchedJoinBlock`3 completion through block
            {
                var localPassed = true;
                var batchedJoin = new BatchedJoinBlock <int, int, int>(99);
                var terminator  = new ActionBlock <Tuple <IList <int>, IList <int>, IList <int> > >(x => { });
                batchedJoin.LinkTo(terminator);
                batchedJoin.Target1.Post(1);
                batchedJoin.Complete();
                localPassed = batchedJoin.Completion.Wait(2000);

                Assert.True(localPassed, string.Format("BatchedJoinBlock`3 completed through block - {0}", localPassed ? "Passed" : "FAILED"));
            }
        }