2009-02-01 6 views
1

Je veux un moyen de pouvoir planifier des rappels, je veux pouvoir enregistrer beaucoup de différents rappels à différents moments à un "Scheduler" -objet. Quelque chose comme ça.Programmer des appels de délégué

public class Foo 
{ 
    public void Bar() 
    { 
     Scheduler s = new Scheduler(); 
     s.Schedule(() => Debug.WriteLine("Hello in an hour!"), DateTime.Now.AddHours(1)); 
     s.Schedule(() => Debug.WriteLine("Hello a week later!"), DateTime.Now.AddDays(7)); 
    } 
} 

La meilleure façon que je peux venir avec la mise en œuvre du planificateur est d'avoir une minuterie en cours d'exécution à l'intérieur à un intervalle donné et chaque fois que l'intervalle est écoulé, je vérifie les callbacks enregistrés et voir s'il est temps de les appeler si c'est le cas. Ceci est assez simple mais a l'inconvénient que vous obtenez seulement la "résolution" de la minuterie. Disons que la minuterie est réglée pour cocher une fois par seconde et que vous enregistrez un rappel pour être appelé en une demi-seconde, il ne peut toujours pas être appelé pendant une seconde entière.

Existe-t-il une meilleure façon de résoudre ce problème?

Répondre

2

Ceci est une bonne approche. Vous devez activer le minuteur de manière dynamique dès que l'événement suivant se produit. Pour ce faire, mettez les travaux dans une file d'attente prioritaire. Après tout, dans tous les cas vous êtes toujours limité à la résolution que le système peut fournir, mais vous devez coder de sorte qu'il soit le seul facteur limitant.

+0

Je jure que j'ai pensé à cette solution l'instance que j'ai frappé le bouton d'envoi sur la question. Il est bon de savoir que c'est la bonne approche. –

1

Une bonne façon de le faire est de varier la durée de votre minuteur: dites-lui de se déclencher quand (mais pas avant) votre premier/prochain événement programmé est dû.

<disclaimer standard sur Windows ne pas être un temps réel du système d'exploitation, de sorte que ses minuteries doivent toujours tous être un peu inexact>

1

Vous ne vraiment besoin le planificateur de se réveiller et d'exécuter quelque chose quand le earlest l'article sur la liste est dû. Après cela, vous réglez la minuterie pour réveiller le programmateur pour la prochaine fois.

Lorsqu'un nouvel élément est ajouté, il vous suffit de comparer son emploi du temps avec celui en cours d'attente. Si c'est le cas, vous annulez le temporisateur actuel et définissez le nouvel élément comme élément programmé suivant.

0

Voici une classe que j'ai écrit pour le faire, en utilisant la classe Timer intégrée de .NET.

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading; 

namespace Sample 
{ 
    /// <summary> 
    /// Use to run a cron job on a timer 
    /// </summary> 
    public class CronJob 
    { 
     private VoidHandler cronJobDelegate; 
     private DateTime? start; 
     private TimeSpan startTimeSpan; 
     private TimeSpan Interval { get; set; } 

     private Timer timer; 

     /// <summary> 
     /// Constructor for a cron job 
     /// </summary> 
     /// <param name="cronJobDelegate">The delegate that will perform the task</param> 
     /// <param name="start">When the cron job will start. If null, defaults to now</param> 
     /// <param name="interval">How long between each execution of the task</param> 
     public CronJob(VoidHandler cronJobDelegate, DateTime? start, TimeSpan interval) 
     { 
      if (cronJobDelegate == null) 
      { 
       throw new ArgumentNullException("Cron job delegate cannot be null"); 
      } 

      this.cronJobDelegate = cronJobDelegate; 
      this.Interval = interval; 

      this.start = start; 
      this.startTimeSpan = DateTime.Now.Subtract(this.start ?? DateTime.Now); 

      this.timer = new Timer(TimerElapsed, this, Timeout.Infinite, Timeout.Infinite); 
     } 

     /// <summary> 
     /// Start the cron job 
     /// </summary> 
     public void Start() 
     { 
      this.timer.Change(this.startTimeSpan, this.Interval); 
     } 

     /// <summary> 
     /// Stop the cron job 
     /// </summary> 
     public void Stop() 
     { 
      this.timer.Change(Timeout.Infinite, Timeout.Infinite); 
     } 

     protected static void TimerElapsed(object state) 
     { 
      CronJob cronJob = (CronJob) state; 
      cronJob.cronJobDelegate.Invoke(); 
     } 
    } 
} 
+0

Merci pour le partage. Bien que ce ne soit pas exactement ce que je recherche car je veux planifier plusieurs rappels avec une instance, c'est très agréable de regarder votre code pour l'inspiration. –

+0

Hm ... idée intéressante. Il ne faudrait probablement pas trop d'efforts pour créer une classe Scheduler statique qui contient une liste de CronJobs enregistrés. – davogones

0

Quartz.Net Planificateur de travaux. Cela classe les classes plutôt que les délégués cependant.

Questions connexes