C# одновременное использование очереди - PullRequest
0 голосов
/ 08 апреля 2020

получил быстрый вопрос.

Должен ли я использовать параллельную очередь, если один поток ставит в очередь, а другой снимает очередь? Есть ли какое-либо состояние гонки / другой риск при использовании обычного контейнера в этом сценарии (1 читатель и 1 писатель)?

1 Ответ

1 голос
/ 08 апреля 2020

С помощью ConcurrentQueue вы можете безопасно вызывать методы Enqueue и TryDequeue из нескольких потоков параллельно. Здесь нет условий гонки. Вы можете делать это целый день 1000000 раз в секунду, без проблем (при условии, что вы не будете использовать всю доступную память в любой момент). Однако может возникнуть состояние гонки, если вы хотите подождать, пока предмет станет доступным, если его нет. Например, потребительский поток может работать в al oop следующим образом:

while (true)
{
    if (!queue.IsEmpty)
    {
        queue.TryDequeue(out var item); // Race condition!
        Process(item);
    }
    else
    {
        Thread.Sleep(50);
    }
}

Этот код имеет условие состязания между вызовами на IsEmpty и TryDequeue. Тем временем очередь может быть освобождена другим потоком. Это условие гонки можно устранить, просто сняв проверку IsEmpty:

while (true)
{
    if (queue.TryDequeue(out var item)) // Fixed
    {
        Process(item);
    }
    else
    {
        Thread.Sleep(50);
    }
}

Это неэффективно. Поток будет делать непроизводительные циклы, и когда элемент станет доступным, он получит его через некоторое время. Также обратите внимание, что в очереди нет способа уведомить поток о том, что он завершен, и больше никогда не будет больше элементов. Обе эти проблемы решаются с помощью специализированного класса BlockingCollection.

foreach (var item in blockingCollection.GetConsumingEnumerable())
{
    Process(item);
}

Метод GetConsumingEnumerable обеспечивает мгновенное уведомление либо о новом элементе, либо для пополнения коллекции.

Класс BlockingCollection имеет недостаток. Как следует из его названия, он блокирует текущий поток во время ожидания. Если это то, чего вы хотели бы избежать, вы можете посмотреть здесь для краткого обзора асинхронных альтернатив.

...