繁体   English   中英

在现有的IProducerConsumerCollection(T)上使用BlockingCollection(T)

[英]Using BlockingCollection(T) on existing IProducerConsumerCollection(T)

我正在从接口中暴露IProducerConsumerCollection(T) ,该接口将定期添加项目以供另一个线程使用。

public interface IProducer<T>
{
    IProducerConsumerCollection<T> ProducerCollection { get; }
}

我试图将BlockingCollection(T)与现有集合一起使用,但是似乎不支持直接添加到IProducerConsumerCollection(T)

var queue = new ConcurrentQueue<string>();
var blockingCollection = new BlockingCollection<string>(queue);

var task1 = Task.Run(() => {
    Console.WriteLine("Dequeued " + blockingCollection.Take());
    Console.WriteLine("Dequeued " + blockingCollection.Take());
});

var task2 = Task.Run(() => {
    Console.WriteLine("Enqueueing Hello");
    queue.Enqueue("Hello");

    Console.WriteLine("Enqueueing World");
    queue.Enqueue("World");
});

Task.WaitAll(task1, task2);

这将无限期地挂起,因为BlockingCollection(T)将不会注意到新项。

是否具有与BlockingCollection(T).Take方法类似的功能,或者有什么比以下方法更简单的方法:

static async Task<T> TakeAsync<T>(
    IProducerConsumerCollection<T> collection,
    CancellationToken token
)
{
    T result;

    while(!collection.TryTake(out result))
    {
        await Task.Yield();
        token.ThrowIfCancellationRequested();
    }

    return result;
}

这将无限期地挂起,因为BlockingCollection(T)将不会注意到新项。

确实如此-因为您是直接添加到queue 从文档中:

不要直接修改基础集合。 使用BlockingCollection<T>方法添加或删除元素。 如果直接更改基础集合,则BlockingCollection<T>对象可能会损坏。

因此,您对queue.Enqueue的调用应改用blockingCollection

TaskAsync方面,您可以使用TryTake并使用Infinite (-1)超时...但是您可能也想阅读Stephen Cleary关于类似主题的博客文章 ...

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM