3

シングルスレッドループを使用する場合、スレッドをスリープ状態にすることで(つまりThread.Sleep(1000/MessagesPerSecond))、1秒あたりに送信されるメッセージを簡単に制限できましたが、並列スレッドに拡張したため、これは正しく機能しなくなりました。

並列スレッドを使用しているときに送信されるメッセージを抑制する方法について誰かが提案していますか?

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

   // Code here

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

2 に答える 2

4

AutoResetEventとタイマーを使用します。タイマーが起動するたびにSet、AutoResetEventを設定します。

WaitOne次に、送信直前にAutoResetEventでメッセージを送信するプロセスを用意します。

    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();
    }
于 2010-07-13T18:23:15.953 に答える
2

共有ConcurrentQueueの使用を検討することもできます。これにより、並列ループに準備されたメッセージが入力されます。System.Threading.Timerを使用して、希望の間隔でキューからメッセージをプルし、送信します。この設計は、送信するメッセージの作成に費用がかかる場合にのみ意味があることに注意してください。メッセージの実際の送信がコストのかかる部分である場合、ループを並行して実行する理由はありません。

メッセージの送信後にタイマーを停止する必要がある場合は、追加の作業を行う必要がありますが、この設計は、非同期メッセージキューを処理する必要があるスロットルされたメッセージ送信者には適しています。考慮すべきもう1つの境界ケースは、「メッセージの積み上げ」です。この場合、メッセージは処理できるよりも速くキューに入れられます。この場合(バグを示している可能性があるため)、またはBlockingCollectionを使用してエラーを生成することを検討することをお勧めします。

于 2010-07-13T19:14:14.853 に答える