awaitable Task based queue

前端 未结 9 1179
礼貌的吻别
礼貌的吻别 2020-11-27 14:44

I\'m wondering if there exists an implementation/wrapper for ConcurrentQueue, similar to BlockingCollection where taking from the collection does not block, but is instead a

9条回答
  •  离开以前
    2020-11-27 15:44

    Simple approach with C# 8.0 IAsyncEnumerable and Dataflow library

    // Instatiate an async queue
    var queue = new AsyncQueue();
    
    // Then, loop through the elements of queue.
    // This loop won't stop until it is canceled or broken out of
    // (for that, use queue.WithCancellation(..) or break;)
    await foreach(int i in queue) {
        // Writes a line as soon as some other Task calls queue.Enqueue(..)
        Console.WriteLine(i);
    }
    

    With an implementation of AsyncQueue as follows:

    public class AsyncQueue : IAsyncEnumerable
    {
        private readonly SemaphoreSlim _enumerationSemaphore = new SemaphoreSlim(1);
        private readonly BufferBlock _bufferBlock = new BufferBlock();
    
        public void Enqueue(T item) =>
            _bufferBlock.Post(item);
    
        public async IAsyncEnumerator GetAsyncEnumerator(CancellationToken token = default)
        {
            // We lock this so we only ever enumerate once at a time.
            // That way we ensure all items are returned in a continuous
            // fashion with no 'holes' in the data when two foreach compete.
            await _enumerationSemaphore.WaitAsync();
            try {
                // Return new elements until cancellationToken is triggered.
                while (true) {
                    // Make sure to throw on cancellation so the Task will transfer into a canceled state
                    token.ThrowIfCancellationRequested();
                    yield return await _bufferBlock.ReceiveAsync(token);
                }
            } finally {
                _enumerationSemaphore.Release();
            }
    
        }
    }
    

提交回复
热议问题