.NET производитель-потребитель вопросы - PullRequest
1 голос
/ 31 марта 2011

Я пишу относительно простое "прокси" приложение для веб-сервиса.Общая идея заключается в том, что TCP-сервер (с асинхронными соединениями) будет считывать (строки) данные с клиентов и помещать эти данные (как часть функции обратного вызова read) в одну из двух очередей (Q1 и Q2).Другой поток прочитает данные в этих очередях и передаст их веб-службе.Данные в 1-м квартале должны иметь приоритет над любыми данными, которые могут быть в 2-м.

Я читал о шаблоне «производитель / потребитель», и, похоже, именно это я и пытаюсь реализовать в отношенииочереди.Поскольку мои операции enqueue и dequeue будут выполняться в разных потоках, кажется очевидным, что мои очереди должны быть безопасными для потоков и поддерживать какой-то механизм блокировки?Это приложение .NET 4.0, и я видел документы по новым классам BlockingCollection и ConcurrentQueue, но я точно не уверен, в чем разница, и как бы я реализовал их в этом сценарии.Кто-нибудь может пролить немного света на это?Спасибо!

Ответы [ 2 ]

2 голосов
/ 01 апреля 2011

Я бы сделал это, как в следующем классе. Вы вызываете Enqueue(), когда создаете элемент, чтобы добавить его в одну из очередей. Этот метод всегда возвращает (почти) сразу. В другой ветке вы звоните Dequeue(), когда будете готовы потреблять предмет. Он пытается сначала взять из очереди с высоким приоритетом. Если в данный момент нет ни одной позиции ни в одной из очередей, вызов блокируется. Когда вы закончите продюсировать, вы звоните Complete(). После того, как этот вызов сделан, и обе очереди пусты, следующий вызов (или текущий заблокированный вызов) на Dequeue() выбрасывает InvalidOperationException.

Если ваш производитель (производители) могут быть быстрее, чем ваши потребители в течение длительных периодов времени, вы должны ограничить очереди (new BlockingCollection<T>(capacity)). Но в этом случае, если у вас есть только один поток, который производит элементы как с низким, так и с высоким приоритетом, возможно, что элементы с высоким приоритетом должны будут ожидать элементы с низким приоритетом. Вы могли бы исправить это, имея один поток для создания элементов с высоким приоритетом и один для элементов с низким приоритетом. Или вы можете связать только очередь с высоким приоритетом и надеяться, что вы не получите миллион наименований с низким приоритетом одновременно.

class Worker<T>
{
    BlockingCollection<T> m_highPriorityQueue = new BlockingCollection<T>();
    BlockingCollection<T> m_lowPriorityQueue = new BlockingCollection<T>();

    public void Enqueue(T item, bool highPriority)
    {
        BlockingCollection<T> queue;
        if (highPriority)
            queue = m_highPriorityQueue;
        else
            queue = m_lowPriorityQueue;

        queue.Add(item);
    }

    public T Dequeue()
    {
        T result;

        if (!m_highPriorityQueue.IsCompleted)
        {
            if (m_highPriorityQueue.TryTake(out result))
                return result;
        }

        if (!m_lowPriorityQueue.IsCompleted)
        {
            if (m_lowPriorityQueue.TryTake(out result))
                return result;
        }

        if (m_highPriorityQueue.IsCompleted && m_lowPriorityQueue.IsCompleted)
            throw new InvalidOperationException("All work is done.");
        else
        {
            try
            {
                BlockingCollection<T>.TakeFromAny(
                    new[] { m_highPriorityQueue, m_lowPriorityQueue },
                    out result);
            }
            catch (ArgumentException ex)
            {
                throw new InvalidOperationException("All work is done.", ex);
            }

            return result;
        }
    }

    public void Complete()
    {
        m_highPriorityQueue.CompleteAdding();
        m_lowPriorityQueue.CompleteAdding();
    }
}
0 голосов
/ 31 марта 2011

BlockingCollection по умолчанию использует ConcurrentQueue.Должно быть хорошо подходит для вашего приложения.Это может быть проще, если вы используете F # с почтовым ящиком и асинхронными блоками.Я сделал пример поста общей реализации ранее.

Отображение / уменьшение с помощью агента F # или MailboxProcessor

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...