Hy,我正在使用MSDN中描述的SocketAsyncEventArgsPool。
对于每个TCP客户端,我有一个50个SocketAsyncEventArgs的自有池(Stack),用于从服务器写入客户端。 所以,这工作正常,但在重新启动客户端或服务器时,我有一个向客户端发送许多消息的函数,并且对于每个消息,从我的池中取出一个SocketAsyncEventArgs。当消息太多时,我的Pool为空,并且没有可用于发送的免费SocketAsyncEventArgs对象,此消息将不会发送给客户端。
有没有可能在不增加我的游泳池的情况下避免这种情况?感谢!!!
答案 0 :(得分:0)
如果您不想增加游泳池的大小,并假设您在使用后正确返回每个SocketAsyncEventArgs
,则可以使用BlockingCollection来保留所需的SocketAsyncEventArgs
数量。在将项目返回到集合之前,消费者将不再需要消费。
<强>更新强>
以下是一些示例代码,它创建一个大小为1的BlockingCollection
并触发一些消费者同时处理。每个消费者从集合中获取一个项目来处理它,同时在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
答案 1 :(得分:0)
如果池为空,只需创建一个新对象。这应该是一个罕见的事件。性能不应受到影响。
您还可以通过在不再使用时将新创建的对象添加回池中来动态增加池大小。这样,池大小不断增加,直到满足所有需求。