예제 #1
0
        private Func <WeakReference <ConcurrentAsyncEnumerator <T> >, Task> BuildProducerWrapperFactory(
            Func <ConcurrentAsyncProducer <T>, Task> producerFunc
            )
        {
            return(async weakEnumerator =>
            {
                ConcurrentAsyncEnumerator <T> enumerator;
                weakEnumerator.TryGetTarget(out enumerator);
                Trace2("Producer container started");
                var producer = new ConcurrentAsyncProducer <T>(item => enumerator.Yield(item), _cancellationToken);

                try
                {
                    // Wait for the consumer to call MoveNext() the first time.
                    // This is only necessary to synchronize the enumerator when the
                    // producer is started.
                    await enumerator._emitNextValue;
                    Trace2("Invoker user produder factory");

                    await producerFunc(producer);

                    enumerator.EndOfStream();
                }
                catch (OperationCanceledException)
                {
                    // The consumer decided to stop the enumeration (by calling Dispose or DisposeAsync).
                    // The idea here is to make sure that any code after the call to Yield that caused
                    // this exception is not executed.
                    // Throwing an exception is the only way to ensure that resources are cleaned up
                    // correctly (try/catch/finally).
                    //
                    // In the the case where
                    // * The consumer cancel the enumeration by calling Dispose (or DisposeAsync)
                    // * The consumer invoke Yield again
                    // * Yield will then throw an ObjectDisposedException to signal
                    // that something is not working as intended.
                    //
                    // But there are cases that are not easily handled.
                    // If the producer code has a "catch all" clause (catch {} or catch(Exception){})
                    // then the producer need to explicitely handle cooperatively to stop the execution
                    // correctly.

                    enumerator.EndOfStream();
                }
                catch (Exception e)
                {
                    // There was an exception (other than EnumerationAbandonedException)
                    // in the producer code.
                    enumerator.EndOfStream(e);
                    // Ensure that this is propagated in Dispose too
                    throw;
                }
            });
        }
예제 #2
0
        internal ConcurrentAsyncEnumerator(Func <ConcurrentAsyncProducer <T>, Task> producerFunc)
        {
            var producer = new ConcurrentAsyncProducer <T>(async item =>
            {
                await valueBufferBlock.SendAsync(item).ConfigureAwait(false);
            });

            producerFunc(producer).ContinueWith(t =>
            {
                if (t.Exception != null)
                {
                    exception = t.Exception;
                }

                valueBufferBlock.Complete();
            }, TaskContinuationOptions.ExecuteSynchronously);
        }
예제 #3
0
        internal ConcurrentAsyncEnumerator(Func <ConcurrentAsyncProducer <T>, Task> producerFunc)
        {
            _producer = async enumerator =>
            {
                var producer = new ConcurrentAsyncProducer <T>(item => enumerator.Yield(item));

                try
                {
                    // Wait for the consumer to call MoveNext() the first time.
                    // Note that after the first time, this will be always signalled.
                    // This is only necessary to synchronize the enumerator when the
                    // producer is started.
                    await _moveNextSignal.Wait().ConfigureAwait(false);
                    await producerFunc(producer);
                }
                finally
                {
                    enumerator.EndOfStream();
                }
            };
        }
예제 #4
0
 internal ConversionObserver(ConcurrentAsyncProducer <T> producer)
 {
     this.producer = producer;
 }
예제 #5
0
 public static Task ForEach <T>(this IAsyncEnumerable <T> enumerable, ConcurrentAsyncProducer <T> producer)
 {
     return(ForEach(enumerable, loopState => producer.Yield(loopState.Item)));
 }