public async Task DisposeAfterPartialEnumeration() { // ARRANGE var testDisposable = new TestDisposable(); var enumerator = new AsyncEnumerator <int>(async yield => { using (testDisposable) { await yield.ReturnAsync(1); await yield.ReturnAsync(2); await yield.ReturnAsync(3); } }); // ACT await enumerator.MoveNextAsync(); enumerator.Dispose(); // ASSERT Assert.IsTrue(testDisposable.HasDisposed); }
public async Task DisposeByGCAfterPartialEnumeration() { // ARRANGE var testDisposable = new TestDisposable(); var enumerator = new AsyncEnumerator <int>(async yield => { using (testDisposable) { await yield.ReturnAsync(1); await yield.ReturnAsync(2); await yield.ReturnAsync(3); } }); // ACT // Do partial enumeration. await enumerator.MoveNextAsync(); // Instead of calling enumerator.Dispose(), do garbage collection. enumerator = null; GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced, blocking: true); // Give some time to other thread that does the disposal of the enumerator. // (see finalizer of the AsyncEnumerator for details) await Task.Delay(16); // ASSERT Assert.IsTrue(testDisposable.HasDisposed); }
public async Task YieldBreak() { // ARRANGE var asyncEnumerationCanceledExceptionRaised = false; var enumerator = new AsyncEnumerator <int>(async yield => { try { yield.Break(); } catch (AsyncEnumerationCanceledException) { asyncEnumerationCanceledExceptionRaised = true; } await yield.ReturnAsync(1); }); // ACT var result = await enumerator.MoveNextAsync(); await Task.Yield(); // ASSERT Assert.IsFalse(result, "MoveNextAsync must return False due to Yield.Break"); Assert.IsTrue(asyncEnumerationCanceledExceptionRaised, "Yield.Break must throw AsyncEnumerationCanceledException so the enumerator body can perform finalization"); }
public async Task RaceConditionOnEndOfEnumeration() { var enumerator = new AsyncEnumerator <int>(async yield => { await Task.Run(async() => { await yield.ReturnAsync(1); }); }); var moveResult1 = await enumerator.MoveNextAsync(); var moveResult2 = await enumerator.MoveNextAsync(); var moveResult3 = await enumerator.MoveNextAsync(); Assert.IsTrue(moveResult1); Assert.IsFalse(moveResult2); Assert.IsFalse(moveResult3); }
public void CancelEnumeration() { var cts = new CancellationTokenSource(); var enumerator = new AsyncEnumerator <int>(yield => { cts.Cancel(); yield.CancellationToken.ThrowIfCancellationRequested(); return(Task.FromResult(0)); }); Assert.ThrowsAsync <OperationCanceledException>(() => enumerator.MoveNextAsync(cts.Token)); }
public async Task EnumerationMustEndAfterDispose() { // ARRANGE var enumerator = new AsyncEnumerator <int>(async yield => { await yield.ReturnAsync(1); await yield.ReturnAsync(2); }); await enumerator.MoveNextAsync(); // ACT enumerator.Dispose(); bool moveNextResult = await enumerator.MoveNextAsync(); int currentElement = enumerator.Current; // ASSERT Assert.IsFalse(moveNextResult, "MoveNextAsync must return False after Dispose"); Assert.AreEqual(1, currentElement, "Current must not change after Dispose"); }
public async Task MeasureEnumerationTime() { var iterations = 1000000; var enumerator = new AsyncEnumerator <int>(async yield => { for (int i = 0; i < iterations; i++) { await yield.ReturnAsync(1); } }); var sw = Stopwatch.StartNew(); int sum = 0; while (await enumerator.MoveNextAsync()) { sum += enumerator.Current; } var time = sw.Elapsed; Console.WriteLine($"Time taken: {time}, Sum: {sum}"); sw = Stopwatch.StartNew(); sum = 0; foreach (var number in EnumerateNumbers()) { sum += number; } time = sw.Elapsed; Console.WriteLine($"Time taken: {time}, Sum: {sum}"); sw = Stopwatch.StartNew(); sum = 0; int _lock = 0; for (int i = 0; i < iterations; i++) { Interlocked.CompareExchange(ref _lock, 1, 0); var tcs = new TaskCompletionSource <int>(); tcs.TrySetResult(1); sum += await tcs.Task; //await Task.Yield(); //await Task.Yield(); Interlocked.Exchange(ref _lock, 0); } time = sw.Elapsed; Console.WriteLine($"Time taken: {time}, Sum: {sum}"); sw = Stopwatch.StartNew(); sum = 0; var t = Task.FromResult(1); for (int i = 0; i < iterations; i++) { sum += await t; } time = sw.Elapsed; Console.WriteLine($"Time taken: {time}, Sum: {sum}"); }