public void TakeAsyncShouldBeThreadSafe() { const int expected = 10; const int max = 100; var exit = false; var collection = new NagleBlockingCollection <int>(10000000); var take1 = collection.TakeBatch(expected, TimeSpan.FromSeconds(100), CancellationToken.None); var take2 = collection.TakeBatch(expected, TimeSpan.FromSeconds(100), CancellationToken.None); var take3 = collection.TakeBatch(expected, TimeSpan.FromSeconds(100), CancellationToken.None); take1.ContinueWith(t => Console.WriteLine("Take1 done...")); take2.ContinueWith(t => Console.WriteLine("Take2 done...")); take3.ContinueWith(t => Console.WriteLine("Take3 done...")); Task.WhenAll(take1, take2, take3).ContinueWith(x => exit = true); Parallel.ForEach(Enumerable.Range(0, max).ToList(), new ParallelOptions { MaxDegreeOfParallelism = 20 }, async x => { while (exit == false) { await collection.AddAsync(x, CancellationToken.None); Thread.Sleep(100); } }); Console.WriteLine("Left in collection: {0}", collection.Count); Assert.That(take1.Result.Count, Is.EqualTo(expected)); Assert.That(take2.Result.Count, Is.EqualTo(expected)); Assert.That(take3.Result.Count, Is.EqualTo(expected)); Assert.That(collection.Count, Is.LessThan(max - (expected * 3))); }
public async void TakeAsyncShouldReturnEvenWhileMoreDataArrives() { var exit = false; var collection = new NagleBlockingCollection <int>(10000000); var sw = Stopwatch.StartNew(); var dataTask = collection.TakeBatch(10, TimeSpan.FromMilliseconds(5000), CancellationToken.None); var highVolumeAdding = Task.Factory.StartNew(async() => { //high volume of data adds while (exit == false) { await collection.AddAsync(1, CancellationToken.None); Thread.Sleep(5); } }); Console.WriteLine("Awaiting data..."); await dataTask; Assert.That(dataTask.Result.Count, Is.EqualTo(10)); Assert.That(sw.ElapsedMilliseconds, Is.LessThan(5000)); exit = true; Console.WriteLine("Waiting to unwind test..."); await highVolumeAdding; }
public void TakeAsyncShouldPlayNiceWithTPL() { const int expected = 200; const int max = 400; var exit = false; var collection = new NagleBlockingCollection <int>(10000000); var dataTask = collection.TakeBatch(expected, TimeSpan.FromSeconds(100), CancellationToken.None); dataTask.ContinueWith(x => exit = true); Parallel.ForEach(Enumerable.Range(0, max).ToList(), new ParallelOptions { MaxDegreeOfParallelism = 20 }, async x => { while (exit == false) { await collection.AddAsync(x, CancellationToken.None); Thread.Sleep(100); } }); Console.WriteLine("Left in collection: {0}", collection.Count); Assert.That(dataTask.Result.Count, Is.EqualTo(expected)); Assert.That(collection.Count, Is.LessThan(max - expected)); }
private async Task BatchSendAsync() { var outstandingSendTasks = new System.Collections.Concurrent.ConcurrentDictionary <Task, Task>(); while (_nagleBlockingCollection.IsCompleted == false || _nagleBlockingCollection.Count > 0) { List <TopicMessage> batch = null; try { try { batch = await _nagleBlockingCollection.TakeBatch(BatchSize, BatchDelayTime, _stopToken.Token).ConfigureAwait(false); } catch (OperationCanceledException ex) { //TODO log that the operation was canceled, this only happens during a dispose } if (_nagleBlockingCollection.IsCompleted && _nagleBlockingCollection.Count > 0) { batch = batch ?? new List <TopicMessage>(_nagleBlockingCollection.Count); //Drain any messages remaining in the queue and add them to the send batch batch.AddRange(_nagleBlockingCollection.Drain()); } //we want to fire the batch without blocking and then move on to fire another one var sendTask = ProduceAndSendBatchAsync(batch, _stopToken.Token); outstandingSendTasks.TryAdd(sendTask, sendTask); var sendTaskCleanup = sendTask.ContinueWith(result => { if (result.IsFaulted && batch != null) { batch.ForEach(x => x.Tcs.TrySetException(result.ExtractException())); } //TODO add statistics tracking outstandingSendTasks.TryRemove(sendTask, out sendTask); }); } catch (Exception ex) { if (batch != null) { batch.ForEach(x => x.Tcs.TrySetException(ex)); } } } var referenceToOutstanding = outstandingSendTasks.Values.ToList(); if (referenceToOutstanding.Count > 0) { await Task.WhenAll(referenceToOutstanding).ConfigureAwait(false); } }
public async void TakeBatchShouldRemoveItemsFromCollection() { const int expectedCount = 10; var collection = new NagleBlockingCollection <int>(100); await collection.AddRangeAsync(Enumerable.Range(0, expectedCount), CancellationToken.None); var data = await collection.TakeBatch(expectedCount, TimeSpan.FromMilliseconds(100), CancellationToken.None); Assert.That(data.Count, Is.EqualTo(expectedCount)); Assert.That(collection.Count, Is.EqualTo(0)); }
public async void TakeAsyncShouldReturnAsSoonAsBatchSizeArrived() { var collection = new NagleBlockingCollection <int>(100); var dataTask = collection.TakeBatch(10, TimeSpan.FromSeconds(5), CancellationToken.None); collection.AddRangeAsync(Enumerable.Range(0, 10), CancellationToken.None); await dataTask; Assert.That(collection.Count, Is.EqualTo(0)); }
public async void CollectionShouldWaitXForBatchSizeToCollect() { const int expectedDelay = 100; const int expectedCount = 10; var collection = new NagleBlockingCollection <int>(100); await collection.AddRangeAsync(Enumerable.Range(0, expectedCount), CancellationToken.None); var sw = Stopwatch.StartNew(); var data = await collection.TakeBatch(expectedCount + 1, TimeSpan.FromMilliseconds(expectedDelay), CancellationToken.None); Assert.That(sw.ElapsedMilliseconds, Is.GreaterThanOrEqualTo(expectedDelay)); Assert.That(data.Count, Is.EqualTo(expectedCount)); }
public async void CollectonTakeShouldBeAbleToCancel() { var cancelSource = new CancellationTokenSource(); var collection = new NagleBlockingCollection <int>(100); Task.Delay(TimeSpan.FromMilliseconds(100)).ContinueWith(t => cancelSource.Cancel()); var sw = Stopwatch.StartNew(); var data = await collection.TakeBatch(10, TimeSpan.FromMilliseconds(500), cancelSource.Token); sw.Stop(); Assert.That(sw.ElapsedMilliseconds, Is.LessThan(300)); }
public async void CollectionShouldReportCorrectBufferCount() { var collection = new NagleBlockingCollection <int>(100); var dataTask = collection.TakeBatch(10, TimeSpan.FromSeconds(5), CancellationToken.None); await collection.AddRangeAsync(Enumerable.Range(0, 9), CancellationToken.None); Assert.That(collection.Count, Is.EqualTo(9)); collection.AddAsync(1, CancellationToken.None); var data = await dataTask; Assert.That(data.Count, Is.EqualTo(10)); Assert.That(collection.Count, Is.EqualTo(0)); }
public async void EnsureCollectionBlocksAtCapacity() { const int blockingCount = 10; const int expectedCount = 5; var collection = new NagleBlockingCollection <int>(blockingCount); var addTask = Task.Factory.StartNew(() => collection.AddRangeAsync(Enumerable.Range(0, blockingCount + expectedCount), CancellationToken.None).Wait()); TaskTest.WaitFor(() => collection.Count >= blockingCount); Assert.That(collection.Count, Is.EqualTo(blockingCount), "The collection should only contain 10 items."); Assert.That(addTask.Status, Is.EqualTo(TaskStatus.Running), "The task should be blocking."); //unblock the collection await collection.TakeBatch(blockingCount, TimeSpan.FromMilliseconds(100), CancellationToken.None); await addTask; Assert.That(collection.Count, Is.EqualTo(expectedCount)); Assert.That(addTask.Status, Is.EqualTo(TaskStatus.RanToCompletion)); }
public async void EnsureCollectionBlocksAtCapacity() { const int blockingCount = 10; const int expectedCount = 5; var collection = new NagleBlockingCollection<int>(blockingCount); var addTask = Task.Factory.StartNew(() => collection.AddRangeAsync(Enumerable.Range(0, blockingCount + expectedCount), CancellationToken.None).Wait()); TaskTest.WaitFor(() => collection.Count >= blockingCount); Assert.That(collection.Count, Is.EqualTo(blockingCount), "The collection should only contain 10 items."); Assert.That(addTask.Status, Is.EqualTo(TaskStatus.Running), "The task should be blocking."); //unblock the collection await collection.TakeBatch(blockingCount, TimeSpan.FromMilliseconds(100), CancellationToken.None); await addTask; Assert.That(collection.Count, Is.EqualTo(expectedCount)); Assert.That(addTask.Status, Is.EqualTo(TaskStatus.RanToCompletion)); }
public async void CollectionShouldWaitXForBatchSizeToCollect() { const int expectedDelay = 100; const int expectedCount = 10; var collection = new NagleBlockingCollection<int>(100); await collection.AddRangeAsync(Enumerable.Range(0, expectedCount), CancellationToken.None); var sw = Stopwatch.StartNew(); var data = await collection.TakeBatch(expectedCount + 1, TimeSpan.FromMilliseconds(expectedDelay), CancellationToken.None); Assert.That(sw.ElapsedMilliseconds, Is.GreaterThanOrEqualTo(expectedDelay)); Assert.That(data.Count, Is.EqualTo(expectedCount)); }
public async void TakeAsyncShouldReturnAsSoonAsBatchSizeArrived() { var collection = new NagleBlockingCollection<int>(100); var dataTask = collection.TakeBatch(10, TimeSpan.FromSeconds(5), CancellationToken.None); collection.AddRangeAsync(Enumerable.Range(0, 10), CancellationToken.None); await dataTask; Assert.That(collection.Count, Is.EqualTo(0)); }
public async void TakeAsyncShouldReturnEvenWhileMoreDataArrives() { var exit = false; var collection = new NagleBlockingCollection<int>(10000000); var sw = Stopwatch.StartNew(); var dataTask = collection.TakeBatch(10, TimeSpan.FromMilliseconds(5000), CancellationToken.None); var highVolumeAdding = Task.Factory.StartNew(async () => { //high volume of data adds while (exit == false) { await collection.AddAsync(1, CancellationToken.None); Thread.Sleep(5); } }); Console.WriteLine("Awaiting data..."); await dataTask; Assert.That(dataTask.Result.Count, Is.EqualTo(10)); Assert.That(sw.ElapsedMilliseconds, Is.LessThan(5000)); exit = true; Console.WriteLine("Waiting to unwind test..."); await highVolumeAdding; }
public void TakeAsyncShouldPlayNiceWithTPL() { const int expected = 200; const int max = 400; var exit = false; var collection = new NagleBlockingCollection<int>(10000000); var dataTask = collection.TakeBatch(expected, TimeSpan.FromSeconds(100), CancellationToken.None); dataTask.ContinueWith(x => exit = true); Parallel.ForEach(Enumerable.Range(0, max).ToList(), new ParallelOptions { MaxDegreeOfParallelism = 20 }, async x => { while (exit == false) { await collection.AddAsync(x, CancellationToken.None); Thread.Sleep(100); } }); Console.WriteLine("Left in collection: {0}", collection.Count); Assert.That(dataTask.Result.Count, Is.EqualTo(expected)); Assert.That(collection.Count, Is.LessThan(max - expected)); }
public void TakeAsyncShouldBeThreadSafe() { const int expected = 10; const int max = 100; var exit = false; var collection = new NagleBlockingCollection<int>(10000000); var take1 = collection.TakeBatch(expected, TimeSpan.FromSeconds(100), CancellationToken.None); var take2 = collection.TakeBatch(expected, TimeSpan.FromSeconds(100), CancellationToken.None); var take3 = collection.TakeBatch(expected, TimeSpan.FromSeconds(100), CancellationToken.None); take1.ContinueWith(t => Console.WriteLine("Take1 done...")); take2.ContinueWith(t => Console.WriteLine("Take2 done...")); take3.ContinueWith(t => Console.WriteLine("Take3 done...")); Task.WhenAll(take1, take2, take3).ContinueWith(x => exit = true); Parallel.ForEach(Enumerable.Range(0, max).ToList(), new ParallelOptions { MaxDegreeOfParallelism = 20 }, async x => { while (exit == false) { await collection.AddAsync(x, CancellationToken.None); Thread.Sleep(100); } }); Console.WriteLine("Left in collection: {0}", collection.Count); Assert.That(take1.Result.Count, Is.EqualTo(expected)); Assert.That(take2.Result.Count, Is.EqualTo(expected)); Assert.That(take3.Result.Count, Is.EqualTo(expected)); Assert.That(collection.Count, Is.LessThan(max - (expected*3))); }
public async void CollectionShouldReportCorrectBufferCount() { var collection = new NagleBlockingCollection<int>(100); var dataTask = collection.TakeBatch(10, TimeSpan.FromSeconds(5), CancellationToken.None); await collection.AddRangeAsync(Enumerable.Range(0, 9), CancellationToken.None); Assert.That(collection.Count, Is.EqualTo(9)); collection.AddAsync(1, CancellationToken.None); var data = await dataTask; Assert.That(data.Count, Is.EqualTo(10)); Assert.That(collection.Count, Is.EqualTo(0)); }
public async void TakeBatchShouldRemoveItemsFromCollection() { const int expectedCount = 10; var collection = new NagleBlockingCollection<int>(100); await collection.AddRangeAsync(Enumerable.Range(0, expectedCount), CancellationToken.None); var data = await collection.TakeBatch(expectedCount, TimeSpan.FromMilliseconds(100), CancellationToken.None); Assert.That(data.Count, Is.EqualTo(expectedCount)); Assert.That(collection.Count, Is.EqualTo(0)); }
public async void CollectonTakeShouldBeAbleToCancel() { var cancelSource = new CancellationTokenSource(); var collection = new NagleBlockingCollection<int>(100); Task.Delay(TimeSpan.FromMilliseconds(100)).ContinueWith(t => cancelSource.Cancel()); var sw = Stopwatch.StartNew(); var data = await collection.TakeBatch(10, TimeSpan.FromMilliseconds(500), cancelSource.Token); sw.Stop(); Assert.That(sw.ElapsedMilliseconds, Is.LessThan(300)); }