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