2014-06-13 33 views
1

Hy,我正在使用MSDN上描述的SocketAsyncEventArgsPool。C#SocketAsyncEventArgsPool Stack Empty

对于每个TCP客户端,我有一个自己的池(堆栈)的50个SocketAsyncEventArgs从服务器写入客户端。 因此,这工作正常,但重新启动客户端或服务器时,我有一个功能,正在向客户端发送许多消息,并从每个消息一个SocketAsyncEventArgs从我的池中采取。当消息太多时,我的Pool为空,并且没有用于发送的免费SocketAsyncEventArgs对象,此消息不会发送给客户端。

有没有可能避免这种情况,而不增加我的游泳池?谢谢!!!

+0

所以你很乐意等到SocketAsyncEventArgs变得可用? –

+0

我试过了!我编辑了SocketAsyncEventArgsPool类的Pop()函数: – user2964559

回答

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 
+0

好!我阅读了BlockingCollection的文章。所以我应该使用BlockingCollection而不是我的池(StackAsocketEventArgs)?消费者将是我的函数发送消息给客户端?对不起,我不确定我是否真正理解BlockingCollection的正确用法。 :) – user2964559

+0

我已经用一个例子更新了答案,希望它有帮助。 –

0

如果池是空的,只需创建一个新的对象。这应该是一个罕见的事件。性能不应受到影响。

您也可以通过将不再使用的新创建的对象添加回池中来动态增加池大小。这样,游泳池的规模一直在增加,直到满足所有需求。