2014-06-13 31 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

如果池是空的,只需創建一個新的對象。這應該是一個罕見的事件。性能不應受到影響。

您也可以通過將不再使用的新創建的對象添加回池中來動態增加池大小。這樣,游泳池的規模一直在增加,直到滿足所有需求。