2010-07-13 5 views
3

Lorsque vous utilisiez une seule boucle filetée, je pouvais facilement limiter mes messages envoyés par seconde en mettant le thread en veille (c'est-à-dire Thread.Sleep(1000/MessagesPerSecond)), assez facile ... mais maintenant que je l'ai développé en threads parallèles cela ne fonctionne plus correctement.Restriction lors de l'utilisation de Parallel.Pour

Quelqu'un at-il une suggestion sur la façon d'étrangler les messages envoyés lors de l'utilisation de threads Parallel?

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

    // Code here 

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

Répondre

4

Utilisez un AutoResetEvent et un temporisateur. Chaque fois que la minuterie se déclenche, ayez Set l'AutoResetEvent.

Ensuite, ayez votre processus qui envoie les messages WaitOne sur le AutoResetEvent immédiatement avant l'envoi.

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

Vous pourriez envisager d'utiliser un ConcurrentQueue partagé, que votre boucle parallèle peuplerait avec des messages préparés. Utilisez le System.Threading.Timer pour extraire les messages de la file d'attente à l'intervalle souhaité et les envoyer. Notez que cette conception n'a de sens que si la création des messages à envoyer est coûteuse; Si l'envoi effectif des messages est la partie la plus coûteuse, il n'y a pas de raison d'exécuter la boucle en parallèle. Si vous devez arrêter le temporisateur après l'envoi des messages, vous devrez effectuer un travail supplémentaire, mais cette conception fonctionne bien pour un expéditeur de message limité qui doit gérer la mise en file d'attente des messages asynchrones. Un autre cas limite à prendre en compte est l'accumulation de messages, où les messages sont mis en file d'attente plus vite qu'ils ne peuvent être traités. Vous pourriez envisager de générer une erreur dans ce cas (car cela peut indiquer un bug) ou d'utiliser un BlockingCollection.