2010-07-13 34 views
3

當使用單線程循環時,通過將線程置於睡眠狀態(即Thread.Sleep(1000/MessagesPerSecond)),我很容易就能夠限制每秒發送的消息......但現在我已經擴展到並行線程不再正常工作。使用Parallel.For的節流

有沒有人有建議如何限制使用並行線程時發送的消息?

Parallel.For(0, NumberOfMessages, delegate(int i) { 

    // Code here 

    if (MessagesPerSecond != 0) 
     Thread.Sleep(1000/MessagesPerSecond); 
}); 

回答

4

使用AutoResetEvent和計時器。每當定時器發生火災時,都要使用AutoResetEvent Set

然後讓您的進程在發送之前立即在AutoResetEvent上發送消息WaitOne

private static readonly AutoResetEvent _Next = new AutoResetEvent(true); 
    private static Timer _NextTimer; 

    private static void SendMessages(IEnumerable<Message> messages) 
    { 
     if (_NextTimer == null) 
      InitializeTimer(); 

     Parallel.ForEach(
      messages, 
      m => 
      { 
       _Next.WaitOne(); 
       // Do something 
      } 
      ); 
    } 

    private static void SetNext(object state) 
    { 
     _Next.Set(); 
    } 
2

您可以考慮使用一個共享的ConcurrentQueue,你的並行循環將與準備的消息填充。使用System.Threading.Timer按期望的時間間隔從隊列中提取消息併發送。請注意,這種設計只有在創建要發送的消息很昂貴時纔有意義;如果消息的實際發送是昂貴的部分,則沒有理由並行運行循環。

如果您需要在發送消息後停止計時器,則必須執行一些額外的工作,但此設計適用於必須處理異步消息隊列的限制消息發送方。另一個需要考慮的邊界案例是「消息堆積」,消息排隊的速度比他們可以處理的要快。您可能需要考慮在這種情況下生成錯誤(因爲它可能表示錯誤)或使用BlockingCollection