C# SocketAsyncEventArgsPool Стек пуст

Hy, я использую SocketAsyncEventArgsPool, описанный на MSDN.

Для каждого TCP-клиента у меня есть собственный пул (Stack) из 50 SocketAsyncEventArgs для записи с сервера на клиент. Итак, это работает нормально, но при перезапуске Клиента или Сервера у меня есть Функция, которая отправляет много сообщений Клиенту, и для каждого сообщения один SocketAsyncEventArgs берется из моего пула. Когда слишком много сообщений, мой Пул пуст и нет свободного объекта SocketAsyncEventArgs для отправки, и это сообщение не будет отправлено Клиенту.

Есть ли возможность избежать этого без увеличения пула??? Спасибо!!!

2 ответа

Если пул пуст, просто создайте новый объект. Это должно быть редкое событие. Производительность не должна быть затронута.

Вы также можете динамически увеличивать размер пула, добавляя вновь созданный объект обратно в пул, когда он больше не используется. Таким образом, размер пула продолжает расти, пока не будет удовлетворен весь спрос.

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

Обновить

Вот пример кода, который создает BlockingCollection размером 1 и запускает несколько потребителей для одновременной обработки. Каждый покупатель берет элемент из коллекции, чтобы обработать его, и в то же время другие блокируются Take пока элемент не будет добавлен обратно в коллекцию.

При обработке вам, вероятно, потребуется сделать это в try/finally блок, чтобы гарантировать, что элемент всегда добавляется обратно после его обработки в случае возникновения исключения.

Чтобы закрыть коллекцию вы звоните CompleteAdding() и любой заблокирован Take методы бросят InvalidOperationException

public void RunConsumer(BlockingCollection<SocketAsyncEventArgs> collection, int consumerId)
{
    Task.Run( async () =>
    {
        Console.WriteLine("Consumer {0} waiting", consumerId);

        SocketAsyncEventArgs args = null;
        try
        {
            args = collection.Take();
            Console.WriteLine("Consumer {0} processing", consumerId);
            await Task.Delay(5000);
        }
        catch(ObjectDisposedException)
        {
           Console.WriteLine("Consumer {0} collection has been disposed", consumerId);
        }
        catch(InvalidOperationException)
        {
           Console.WriteLine("Consumer {0} collection has been closed", consumerId);
        }
        finally
        {
            // add the item back if collection hasn't been closed.
            if(args != null && !collection.IsAddingCompleted)
                collection.Add(args);
        }

        Console.WriteLine("Consumer {0} finished", consumerId);
    });
}

использование

void Main()
{
    var collection = new BlockingCollection<SocketAsyncEventArgs>(1) { new SocketAsyncEventArgs() };

    RunConsumer(collection, 1);
    RunConsumer(collection, 2);
    RunConsumer(collection, 3);

    Thread.Sleep(9000);
    collection.CompleteAdding();
    Console.ReadLine();
}

Выход

Consumer 1 waiting
Consumer 3 waiting
Consumer 2 waiting
Consumer 1 processing
Consumer 1 finished
Consumer 3 processing
Consumer 2 collection has been closed
Consumer 2 finished
Consumer 3 finished
Другие вопросы по тегам