Это интересный вопрос.Это первый раз, когда я вижу, как кто-то запрашивает очередь блокировки, которая игнорирует дубликаты.Как ни странно, я не смог найти ничего похожего на то, что вы хотите, которое уже существует в BCL.Я говорю, что это странно, потому что BlockingCollection
может принять IProducerConsumerCollection
в качестве базовой коллекции, у которой есть метод TryAdd
, который объявляется способным завершаться ошибкой при обнаружении дубликатов.Проблема в том, что я не вижу конкретной реализации IProducerConsumerCollection
, которая предотвращает дублирование.По крайней мере, мы можем написать свои собственные.
public class NoDuplicatesConcurrentQueue<T> : IProducerConsumerCollection<T>
{
// TODO: You will need to fully implement IProducerConsumerCollection.
private Queue<T> queue = new Queue<T>();
public bool TryAdd(T item)
{
lock (queue)
{
if (!queue.Contains(item))
{
queue.Enqueue(item);
return true;
}
return false;
}
}
public bool TryTake(out T item)
{
lock (queue)
{
item = null;
if (queue.Count > 0)
{
item = queue.Dequeue();
}
return item != null;
}
}
}
Теперь, когда у нас есть IProducerConsumerCollection
, который не принимает дубликаты, мы можем использовать его следующим образом:
public class Example
{
private BlockingCollection<object> queue = new BlockingCollection<object>(new NoDuplicatesConcurrentQueue<object>());
public Example()
{
new Thread(Consume).Start();
}
public void Produce(object item)
{
bool unique = queue.TryAdd(item);
}
private void Consume()
{
while (true)
{
object item = queue.Take();
}
}
}
Вам может не понравитьсямоя реализация NoDuplicatesConcurrentQueue
.Вы, безусловно, можете свободно реализовывать свои собственные, используя ConcurrentQueue
или что-то еще, если считаете, что вам нужна производительность с низким уровнем блокировки, которую обеспечивают коллекции TPL.
Обновление:
Я был в состоянии проверить код этим утром.Есть хорошие и плохие новости.Хорошей новостью является то, что это будет технически работать.Плохая новость заключается в том, что вы, вероятно, не захотите этого делать, потому что BlockingCollection.TryAdd
перехватывает возвращаемое значение из базового метода IProducerConsumerCollection.TryAdd
и выдает исключение при обнаружении false
.Да, это правильно.Он не возвращает false
, как вы ожидаете, и вместо этого генерирует исключение.Я должен быть честным, это и удивительно и смешно.Смысл методов TryXXX в том, что они не должны генерировать исключения.Я глубоко разочарован.