/// <summary> /// Returns the name of the block, based on <see cref="DataflowBlockOptions.NameFormat"/>. /// </summary> /// <remarks> /// If the NameFormat is invalid, returns the exception message. /// </remarks> public static string GetName(IDataflowBlock block, DataflowBlockOptions options) { try { return string.Format ( options.NameFormat, block.GetType ().Name, block.Completion.Id); } catch (FormatException e) { return e.Message; } }
internal void DataflowBlockCreated(IDataflowBlock block, DataflowBlockOptions dataflowBlockOptions) { Contract.Requires(block != null, "Block needed for the ETW event."); Contract.Requires(dataflowBlockOptions != null, "Options needed for the ETW event."); if (IsEnabled(EventLevel.Informational, ALL_KEYWORDS)) { DataflowBlockCreated( Common.GetNameForDebugger(block, dataflowBlockOptions), Common.GetBlockId(block)); } }
static void Example6() { var sourceBlock = new BufferBlock <int>(); var options = new DataflowBlockOptions { BoundedCapacity = 1 }; var targetBlockA = new BufferBlock <int>(options); var targetBlockB = new BufferBlock <int>(options); sourceBlock.LinkTo(targetBlockA); sourceBlock.LinkTo(targetBlockB); }
public PriorityBlock() { var options = new DataflowBlockOptions { BoundedCapacity = 1 }; _highPriorityTarget = new BufferBlock <T>(options); _lowPriorityTarget = new BufferBlock <T>(options); _source = new BufferBlock <T>(options); Task.Run(ForwardMessages); }
public ProcessingBufferBlock(Int32 boundedCapacity, Int32 degreeOfParalellism, CancellationToken cancellation) { _cancellation = cancellation; _semaphore = new SemaphoreSlim(degreeOfParalellism); var options = new DataflowBlockOptions() { BoundedCapacity = boundedCapacity, CancellationToken = cancellation }; _in = new BufferBlock <TIn>(options); _out = new BufferBlock <ProcessingResult <TOut> >(options); StartReadingAsync(); }
public ResourceEnricherBlock(CancellationToken cancellationToken, IResourceEnricher resourceEnricher, ILog log) : base(cancellationToken, maxDegreeOfParallelism: 300) { _log = log; _resourceEnricher = resourceEnricher; var generalDataflowBlockOptions = new DataflowBlockOptions { CancellationToken = cancellationToken }; FailedProcessingResults = new BufferBlock <FailedProcessingResult>(generalDataflowBlockOptions); base.Completion.ContinueWith(_ => { FailedProcessingResults.Complete(); }); }
public ActionPriorityBlock(Action <T> action, ExecutionDataflowBlockOptions opts) { var options = new DataflowBlockOptions() { BoundedCapacity = 1 }; highPriorityTarget = new BufferBlock <T>(options); lowPriorityTarget = new BufferBlock <T>(options); actBlock = new ActionBlock <T>(action, opts); Task.Run(ForwardData); }
public TransformManyBoundedBlock( Func <TInput, IEnumerable <TOutput> > transform, ExecutionDataflowBlockOptions inputOptions, DataflowBlockOptions outputOptions) { Contracts.Requires.That(transform != null); Contracts.Requires.That(inputOptions != null); Contracts.Requires.That(outputOptions != null); this.transform = transform; this.action = new ActionBlock <TInput>(this.EnumerateAsync, inputOptions); this.buffer = new BufferBlock <TOutput>(outputOptions); this.Completion = this.CompleteAsync(); }
private void CreateTplChain(ref BufferBlock <AtomicDispatchChunk> buffer, ref ITargetBlock <AtomicDispatchChunk> broadcaster) { DataflowBlockOptions bufferOptions = new DataflowBlockOptions { BoundedCapacity = 4000, }; var localBuffer = buffer = new BufferBlock <AtomicDispatchChunk>(bufferOptions); Metric.Gauge("atomic-projection-buffer", () => localBuffer.Count, Unit.Items); ExecutionDataflowBlockOptions enhancerExecutionOptions = new ExecutionDataflowBlockOptions { BoundedCapacity = 4000, MaxDegreeOfParallelism = 1, }; var enhancer = new TransformBlock <AtomicDispatchChunk, AtomicDispatchChunk>(c => { _commitEnhancer.Enhance(c.Chunk); return(c); }, enhancerExecutionOptions); buffer.LinkTo(enhancer, new DataflowLinkOptions() { PropagateCompletion = true }); Metric.Gauge("atomic-projection-enhancer-buffer", () => enhancer.InputCount, Unit.Items); ExecutionDataflowBlockOptions consumerExecutionOptions = new ExecutionDataflowBlockOptions { BoundedCapacity = 15000, MaxDegreeOfParallelism = 1, }; var consumers = new List <ITargetBlock <AtomicDispatchChunk> >(); foreach (var item in _consumerBlocks) { //Ok I have a list of atomic projection, we need to create projector for every item. var blocks = item.Value; var consumer = new ActionBlock <AtomicDispatchChunk>(InnerDispatch(item, blocks), consumerExecutionOptions); Metric.Gauge("atomic-projection-consumer-buffer-" + item.Key.Name, () => consumer.InputCount, Unit.Items); KernelMetricsHelper.CreateMeterForAtomicReadmodelDispatcherCount(item.Key.Name); consumers.Add(consumer); } broadcaster = GuaranteedDeliveryBroadcastBlock.Create(consumers, "AtomicPoller", 3000); enhancer.LinkTo(broadcaster, new DataflowLinkOptions() { PropagateCompletion = true }); }
public void DataflowBlockOptionsTest() { var options = new DataflowBlockOptions(); AssertEx.Throws <ArgumentOutOfRangeException>(() => options.BoundedCapacity = -2); AssertEx.Throws <ArgumentOutOfRangeException>(() => options.MaxMessagesPerTask = -2); AssertEx.Throws <ArgumentNullException>(() => options.NameFormat = null); // shouldn't throw options.NameFormat = "{2}"; new BufferBlock <int>(options).ToString(); AssertEx.Throws <ArgumentNullException>(() => options.TaskScheduler = null); }
public static IEnumerable <IDataflowBlock> CreateBlocksWithCancellationToken(CancellationToken cancellationToken) { var dataflowBlockOptions = new DataflowBlockOptions { CancellationToken = cancellationToken }; var executionDataflowBlockOptions = new ExecutionDataflowBlockOptions { CancellationToken = cancellationToken }; var groupingDataflowBlockOptions = new GroupingDataflowBlockOptions { CancellationToken = cancellationToken }; return(CreateBlocksWithOptions(dataflowBlockOptions, executionDataflowBlockOptions, groupingDataflowBlockOptions)); }
public static IEnumerable <IDataflowBlock> CreateBlocksWithNameFormat(string nameFormat) { var dataflowBlockOptions = new DataflowBlockOptions { NameFormat = nameFormat }; var executionDataflowBlockOptions = new ExecutionDataflowBlockOptions { NameFormat = nameFormat }; var groupingDataflowBlockOptions = new GroupingDataflowBlockOptions { NameFormat = nameFormat }; return(CreateBlocksWithOptions(dataflowBlockOptions, executionDataflowBlockOptions, groupingDataflowBlockOptions)); }
/// <summary> /// 初期化処理。 /// </summary> /// <param name="settingObject"></param> /// <param name="token"></param> public void Init(dynamic settingObject, CancellationToken token) { logger.Trace("Init Start"); var opt = new DataflowBlockOptions { CancellationToken = token, }; var buffer = new BufferBlock <PastaLog>(opt); var bloadcast = new BroadcastBlock <PastaLog>(CloneLog, opt); buffer.LinkTo(bloadcast); Target = buffer; Source = bloadcast; logger.Trace("Init End"); }
public ChooserBlock( Action <T1> action1, Action <T2> action2, Action <T3> action3, DataflowBlockOptions dataflowBlockOptions) { Target1 = new ChooseTarget <T1> (this, 0, action1); Target2 = new ChooseTarget <T2> (this, 1, action2); if (action3 != null) { Target3 = new ChooseTarget <T3> (this, 2, action3); } if (dataflowBlockOptions.CancellationToken != CancellationToken.None) { dataflowBlockOptions.CancellationToken.Register(Cancelled); } }
public ISubscriptionTag Subscribe <T>(ISubscriber subscriber, int queueCapacity = 1) { DataflowBlockOptions queueOptions = new DataflowBlockOptions { BoundedCapacity = queueCapacity }; MessageBuffer workerQueue = new MessageBuffer(queueOptions); ISubscriptionTag subscriberTag = subscriber.SubscribeTo(workerQueue); ISubscriptionTag dispatcherTag = this.LinkDispatcherTo <T>(workerQueue); subscriberTag = new CompositeSubscriptionTag(Guid.NewGuid().ToString(), subscriberTag, dispatcherTag); subscribers.AddOrUpdate(subscriberTag.Id, subscriberTag, (o, n) => n); return(subscriberTag); }
public BaseFlowBlock(int capacity = 1000, BlockType procType = BlockType.Transform, int threadCount = 4) { _id = __id; Interlocked.Increment(ref __id); _linkedBlockCompletions = new List <Task>(); ProcType = procType; _onCompletionTasks = new List <Task>(); var options = new DataflowBlockOptions() { BoundedCapacity = capacity }; _buffer = new BufferBlock <TIn>(options); var ops = new DataflowLinkOptions { PropagateCompletion = true }; var executionBlockOptions = new ExecutionDataflowBlockOptions() { MaxDegreeOfParallelism = threadCount, BoundedCapacity = capacity }; switch (procType) { case BlockType.Action: _actionBlock = new ActionBlock <TIn>((item) => { var receivedResult = OnBlockReceived(item); //So that we can actually make a link ItemProcessed?.Invoke(receivedResult); }, executionBlockOptions); _buffer.LinkTo(_actionBlock, ops); break; case BlockType.Transform: _transformer = new TransformBlock <TIn, TOut>( new Func <TIn, TOut>(OnBlockReceived), executionBlockOptions); _transformLinkInstance = _buffer.LinkTo(_transformer, ops); break; default: throw new Exception("Not supported"); } }
public Bus(int inboxCapacity = 10) { this.inboxes = new ConcurrentDictionary <Type, MessageBuffer>(); this.dispatchers = new ConcurrentDictionary <Type, MessageDispatcher>(); this.subscribers = new ConcurrentDictionary <string, ISubscriptionTag>(); this.publishers = new ConcurrentDictionary <string, IPublishingTag>(); this.defaultInboxQueueOptions = new DataflowBlockOptions { BoundedCapacity = inboxCapacity }; this.defaultDistpatcherOptions = new ExecutionDataflowBlockOptions { BoundedCapacity = 1 }; }
/// <summary> /// Runs calculation. /// </summary> public async Task RunCalculationAsync() { IDictionary <string, long> resultDictionary = new ConcurrentDictionary <string, long>(); var extractBlockOptions = new DataflowBlockOptions { BoundedCapacity = 1 }; var calculationBlockOptions = new ExecutionDataflowBlockOptions() { BoundedCapacity = Environment.ProcessorCount * MaxBufferSize * 100, MaxDegreeOfParallelism = Environment.ProcessorCount * 100 }; var linkOptions = new DataflowLinkOptions { PropagateCompletion = true }; var getBlocks = new BufferBlock <string>(extractBlockOptions); var calculateFrequencies = new ActionBlock <string>( (text) => { frequencyCalculator.CalculateFrequencies(text, resultDictionary); }, calculationBlockOptions); getBlocks.LinkTo(calculateFrequencies, linkOptions); string buffer = dataReader.GetBlock(); while (buffer != null) { await getBlocks.SendAsync(buffer); buffer = dataReader.GetBlock(); } getBlocks.Complete(); await Task.WhenAll(calculateFrequencies.Completion); dataWriter.SaveDictionary(new SortedDictionary <string, long>(resultDictionary)); }
public ShellAsync( IO.Input.InputManagerAsync inputManagerAsync, Crawlers.CrawlersManagerAsync crawlersManagerAsync, Appraisers.AppraisersManagerAsync appraisersManagerAsync, IO.Output.OutputManagerAsync outputManagerAsync, int boundedCapacity) { InputManagerAsync = inputManagerAsync.ThrowIfNull(nameof(inputManagerAsync)); CrawlersManagerAsync = crawlersManagerAsync.ThrowIfNull(nameof(crawlersManagerAsync)); AppraisersManagerAsync = appraisersManagerAsync.ThrowIfNull(nameof(appraisersManagerAsync)); OutputManagerAsync = outputManagerAsync.ThrowIfNull(nameof(outputManagerAsync)); _boundedCapacity = boundedCapacity; _dataFlowOptions = new DataflowBlockOptions { BoundedCapacity = _boundedCapacity }; }
private void CreateTplChain() { DataflowBlockOptions bufferOptions = new DataflowBlockOptions(); bufferOptions.BoundedCapacity = _bufferSize; _buffer = new BufferBlock <IChunk>(bufferOptions); ExecutionDataflowBlockOptions executionOption = new ExecutionDataflowBlockOptions(); executionOption.BoundedCapacity = _bufferSize; _broadcaster = GuaranteedDeliveryBroadcastBlock.Create(_consumers, _id, 3000); _buffer.LinkTo(_broadcaster, new DataflowLinkOptions() { PropagateCompletion = true }); }
public EtlExecutionDataflowBlockOptions( DataflowBlockOptions producerDataflowBlockOptions, ExecutionDataflowBlockOptions extractDataflowBlockOptions, ExecutionDataflowBlockOptions onExtractCompletedDataflowBlockOptions, ExecutionDataflowBlockOptions transformDataflowBlockOptions, ExecutionDataflowBlockOptions onTransformCompletedDataflowBlockOptions, ExecutionDataflowBlockOptions loadDataflowBlockOptions, ExecutionDataflowBlockOptions onLoadCompletedDataflowBlockOptions ) { LoadDataflowBlockOptions = loadDataflowBlockOptions ?? throw new ArgumentNullException(nameof(loadDataflowBlockOptions)); ExtractDataflowBlockOptions = extractDataflowBlockOptions ?? throw new ArgumentNullException(nameof(extractDataflowBlockOptions)); TransformDataflowBlockOptions = transformDataflowBlockOptions ?? throw new ArgumentNullException(nameof(transformDataflowBlockOptions)); ProducerDataflowBlockOptions = producerDataflowBlockOptions ?? throw new ArgumentNullException(nameof(producerDataflowBlockOptions)); OnLoadCompletedDataflowBlockOptions = onLoadCompletedDataflowBlockOptions ?? throw new ArgumentNullException(nameof(onLoadCompletedDataflowBlockOptions)); OnExtractCompletedDataflowBlockOptions = onExtractCompletedDataflowBlockOptions ?? throw new ArgumentNullException(nameof(onExtractCompletedDataflowBlockOptions)); OnTransformCompletedDataflowBlockOptions = onTransformCompletedDataflowBlockOptions ?? throw new ArgumentNullException(nameof(onTransformCompletedDataflowBlockOptions)); }
/// <summary> /// Performs shallow clone of the options. /// </summary> public static DataflowBlockOptions Clone([NotNull] this DataflowBlockOptions source) { if (source == null) { throw new ArgumentNullException(nameof(source)); } var result = new DataflowBlockOptions { BoundedCapacity = source.BoundedCapacity, CancellationToken = source.CancellationToken, MaxMessagesPerTask = source.MaxMessagesPerTask, NameFormat = source.NameFormat, TaskScheduler = source.TaskScheduler }; return(result); }
public ISubscriptionTag Subscribe <T>(ISubscriber subscriber, int queueCapacity = 1) { this.logService.Info("Creating subscription to {0} with the queue capacity equals: {1}.", typeof(T), queueCapacity); DataflowBlockOptions queueOptions = new DataflowBlockOptions { BoundedCapacity = queueCapacity }; MessageBuffer workerQueue = new MessageBuffer(queueOptions); ISubscriptionTag subscriberTag = subscriber.SubscribeTo(workerQueue); ISubscriptionTag dispatcherTag = this.LinkDispatcherTo <T>(workerQueue); subscriberTag = new CompositeSubscriptionTag(Guid.NewGuid().ToString(), subscriberTag, dispatcherTag); subscribers.AddOrUpdate(subscriberTag.Id, subscriberTag, (o, n) => n); return(subscriberTag); }
void BlockInit() { var executionblockOptions = new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = Context.TestOptions.MaxDegreeOfParallelism }; var dataflowBlockOptions = new DataflowBlockOptions { CancellationToken = Context.CancellationTokenSource.Token }; _executionQueueBlock = new BufferBlock <CrawledPage>(dataflowBlockOptions); _testBlock = new TransformBlock <CrawledPage, PageTestedResult>(new Func <CrawledPage, Task <PageTestedResult> >(TestPage), executionblockOptions); _notificationBlock = new ActionBlock <PageTestedResult>(new Action <PageTestedResult>(PageTestСompleted), executionblockOptions); _executionQueueBlock.LinkTo(_testBlock); _testBlock.LinkTo(_notificationBlock); _executionQueueBlock.Completion.ContinueWith(t => { if (t.IsFaulted) { ((IDataflowBlock)_testBlock).Fault(t.Exception); } else { _testBlock.Complete(); } }); _testBlock.Completion.ContinueWith(t => { if (t.IsFaulted) { ((IDataflowBlock)_notificationBlock).Fault(t.Exception); } else { _notificationBlock.Complete(); } }); }
public static ITargetBlock <T> Create <T>( Action <IReadOnlyList <T> > action, int maxBatchSize, Batching batching, DataflowBlockOptions options) { Contracts.Requires.That(action != null); Contracts.Requires.That(options != null); switch (batching) { case Batching.Dynamic: options = options.CreateCopy(); options.BoundedCapacity = maxBatchSize; return(new DynamicBatchActionBlock <T>(action, options)); case Batching.Static: return(new StaticBatchActionBlock <T>(action, maxBatchSize, options)); default: throw InvalidEnumArgument.CreateException(nameof(batching), batching); } }
public static async Task Test() { var blockOptions = new DataflowBlockOptions() { }; var bufferBlock = new BufferBlock <int>(); var actionBlock = new ActionBlock <int[]>(async i => { await Task.Delay(1); Console.WriteLine(i); }); var transformBlock = new TransformBlock <int, string>(async i => { await Task.Delay(1); return(i.ToString()); }); var batchBlock = new BatchBlock <int>(10); IDisposable link = batchBlock.LinkTo(actionBlock); }
public ContinueBlock(ITargetBlock <T> target, Func <Task> continuation, DataflowBlockOptions options) { this.target = target; this.Completion = this.target.Completion.ContinueWith( (task, obj) => { if (task.IsFaulted) { return(task); } return(((Func <Task>)obj !).Invoke()); }, continuation, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, options.TaskScheduler) .Unwrap(); }
public Bus(int inboxCapacity = 10, ILogServiceProvider logServiceProvider = null) { this.inboxes = new ConcurrentDictionary <Type, MessageBuffer>(); this.dispatchers = new ConcurrentDictionary <Type, MessageDispatcher>(); this.subscribers = new ConcurrentDictionary <string, ISubscriptionTag>(); this.publishers = new ConcurrentDictionary <string, IPublishingTag>(); this.logServiceProvider = logServiceProvider ?? new NullLogServiceProvider(); this.logService = this.logServiceProvider.GetLogServiceOf(typeof(Bus)); this.defaultInboxQueueOptions = new DataflowBlockOptions { BoundedCapacity = inboxCapacity }; this.defaultDistpatcherOptions = new ExecutionDataflowBlockOptions { BoundedCapacity = 1 }; this.logService.Info("Started the bus instance with the inbox capacity equals: {0}.", inboxCapacity); }
private void CreateTplChain(ref BufferBlock <AtomicDispatchChunk> buffer, ref ITargetBlock <AtomicDispatchChunk> broadcaster) { DataflowBlockOptions bufferOptions = new DataflowBlockOptions { BoundedCapacity = 4000, }; var localBuffer = buffer = new BufferBlock <AtomicDispatchChunk>(bufferOptions); Metrics.Metric.Gauge("atomic-projection-buffer", () => localBuffer.Count, Metrics.Unit.Items); ExecutionDataflowBlockOptions executionOption = new ExecutionDataflowBlockOptions { BoundedCapacity = 4000, }; var enhancer = new TransformBlock <AtomicDispatchChunk, AtomicDispatchChunk>(c => { _commitEnhancer.Enhance(c.Chunk); //This was already done by the poller, but we are investigating on using directly a NStore poller. return(c); }, executionOption); buffer.LinkTo(enhancer, new DataflowLinkOptions() { PropagateCompletion = true }); Metrics.Metric.Gauge("atomic-projection-enhancer-buffer", () => (Double)enhancer.InputCount, Metrics.Unit.Items); var consumers = new List <ITargetBlock <AtomicDispatchChunk> >(); foreach (var item in _consumerBlocks) { //Ok I have a list of atomic projection, we need to create projector for every item. var blocks = item.Value; var consumer = new ActionBlock <AtomicDispatchChunk>(InnerDispatch(item, blocks), executionOption); Metrics.Metric.Gauge("atomic-projection-consumer-buffer-" + item.Key.Name, () => consumer.InputCount, Metrics.Unit.Items); consumers.Add(consumer); } broadcaster = GuaranteedDeliveryBroadcastBlock.Create(consumers, "AtomicPoller", 3000); enhancer.LinkTo(broadcaster, new DataflowLinkOptions() { PropagateCompletion = true }); }
static void Main(string[] args) { Console.Title = "Machine Intelligence (Text Analytics) with TPL Data Flows"; // CONFIG // Instantiate new ML.NET Context // Note: MlContext is thread-safe var mlContext = new MLContext(100); // GET Current Environment Folder var currentEnrichmentFolder = System.IO.Path.Combine(Environment.CurrentDirectory, "EnrichedDocuments"); System.IO.Directory.CreateDirectory(currentEnrichmentFolder); // SET language to English StopWordsRemovingEstimator.Language language = StopWordsRemovingEstimator.Language.English; // SET the max degree of parallelism // Note: Default is to use 75% of the workstation or server cores. // Note: If cores are hyperthreaded, adjust accordingly (i.e. multiply *2) var isHyperThreaded = false; var executionDataFlowOptions = new ExecutionDataflowBlockOptions(); executionDataFlowOptions.MaxDegreeOfParallelism = // Use 75% of the cores, if hyper-threading multiply cores *2 Convert.ToInt32(Math.Ceiling((Environment.ProcessorCount * 0.75) * (isHyperThreaded ? 2: 1))); // SET the Data Flow Block Options // This controls the data flow from the Producer level var dataFlowBlockOptions = new DataflowBlockOptions { BoundedCapacity = 5, MaxMessagesPerTask = 5 }; // SET the data flow pipeline options // Note: Set MaxMessages to the number of books to process // Note: For example, setting MaxMessages to 2 will run only two books through the pipeline var dataFlowLinkOptions = new DataflowLinkOptions { PropagateCompletion = true, //MaxMessages = 1 };
//[Fact(Skip = "Outerloop")] public void TestBufferBlockCompletionOrder() { const int ITERATIONS = 1000; for (int iter = 0; iter < ITERATIONS; iter++) { var cts = new CancellationTokenSource(); var options = new DataflowBlockOptions() { CancellationToken = cts.Token }; var buffer = new BufferBlock <int>(options); buffer.Post(1); cts.Cancel(); try { buffer.Completion.Wait(); } catch { } Assert.False(buffer.Count != 0, string.Format("Iteration {0}: Completed before clearing messages.", iter)); } }
public void RunBoundingTests() { var options = new DataflowBlockOptions() { BoundedCapacity = ITargetBlockTestHelper.BOUNDED_CAPACITY }; var executionOptions = new ExecutionDataflowBlockOptions() { BoundedCapacity = ITargetBlockTestHelper.BOUNDED_CAPACITY }; var greedyOptions = new GroupingDataflowBlockOptions() { BoundedCapacity = ITargetBlockTestHelper.BOUNDED_CAPACITY, Greedy = true }; var nonGreedyOptions = new GroupingDataflowBlockOptions() { BoundedCapacity = ITargetBlockTestHelper.BOUNDED_CAPACITY, Greedy = false }; // "Normal" target blocks Assert.True(ITargetBlockTestHelper.TestBoundingTarget<int, int>(new ActionBlock<int>((Action<int>)ITargetBlockTestHelper.BoundingAction, executionOptions), greedy: true)); // BatchBlock Assert.True(ITargetBlockTestHelper.TestBoundingTarget<int, int[]>(new BatchBlock<int>(ITargetBlockTestHelper.BOUNDED_CAPACITY, greedyOptions), greedy: true)); Assert.True(ITargetBlockTestHelper.TestBoundingTarget<int, int[]>(new BatchBlock<int>(ITargetBlockTestHelper.BOUNDED_CAPACITY, nonGreedyOptions), greedy: false)); // JoinBlock Assert.True(ITargetBlockTestHelper.TestBoundingJoin2<int>(new JoinBlock<int, int>(greedyOptions), greedy: true)); Assert.True(ITargetBlockTestHelper.TestBoundingJoin3<int>(new JoinBlock<int, int, int>(nonGreedyOptions), greedy: false)); // JoinBlock.Target Assert.True(ITargetBlockTestHelper.TestBoundingGreedyJoinTarget2<int>(new JoinBlock<int, int>(greedyOptions), testedTargetIndex: 1)); Assert.True(ITargetBlockTestHelper.TestBoundingGreedyJoinTarget3<int>(new JoinBlock<int, int, int>(greedyOptions), testedTargetIndex: 2)); }
public async Task TestChoose_LinkTracking() { for (int n = 2; n <= 3; n++) { foreach (bool cancelBeforeChoose in DataflowTestHelpers.BooleanValues) { int[] linkCounts = new int[n], unlinkCounts = new int[n]; ISourceBlock<int>[] sources = Enumerable.Range(0, n).Select(i => new DelegatePropagator<int, int> { LinkToDelegate = (target, linkOptions) => { Interlocked.Increment(ref linkCounts[i]); return new DelegateDisposable { DisposeDelegate = () => Interlocked.Increment(ref unlinkCounts[i]) }; } }).ToArray(); var cts = new CancellationTokenSource(); if (cancelBeforeChoose) cts.Cancel(); var options = new DataflowBlockOptions { MaxMessagesPerTask = 1, CancellationToken = cts.Token }; Action<int> nop = x => { }; Task<int> choose = n == 2 ? DataflowBlock.Choose(sources[0], nop, sources[1], nop, options) : DataflowBlock.Choose(sources[0], nop, sources[1], nop, sources[2], nop, options); if (!cancelBeforeChoose) cts.Cancel(); await Assert.ThrowsAnyAsync<OperationCanceledException>(() => choose); int expectedLinkCount = cancelBeforeChoose ? 0 : 1; Assert.All(linkCounts, i => Assert.Equal(expected: expectedLinkCount, actual: i)); Assert.All(unlinkCounts, i => Assert.Equal(expected: expectedLinkCount, actual: i)); } } }