Come posso generare un evento ogni ora (o specifico intervallo di tempo ogni ora) in .NET?

StackOverflow https://stackoverflow.com/questions/307798

  •  08-07-2019
  •  | 
  •  

Domanda

Sto lavorando a un piccolo crawler Web che verrà eseguito nella barra delle applicazioni e eseguirà la scansione di un sito Web ogni ora all'ora.

Qual è il modo migliore per ottenere .NET per generare un evento ogni ora o qualche altro intervallo per eseguire alcune attività. Ad esempio, voglio organizzare un evento ogni 20 minuti in base al tempo. L'evento sarà sollevato a:

00:20
00:40
01:00
01:20
01:40

e così via. Il modo migliore a cui riesco a pensare di farlo è creare un loop su un thread, che controlla costantemente se il tempo è divisibile per un determinato intervallo e genera un evento di richiamata se viene raggiunto il tempo. Sento che deve esserci un modo migliore.

Userei un Timer ma preferirei qualcosa che segue un "programma" che corre ogni ora o qualcosa del genere.

Senza configurare la mia applicazione nell'utilità di pianificazione di Windows è possibile?

UPDATE:
Sto aggiungendo il mio algoritmo per il calcolo dell'intervallo di tempo per un timer. Questo metodo richiede un " minuto " parametro, ovvero a che ora il timer dovrebbe attivare un segno di spunta. Ad esempio, se il " minuto " Il parametro è 20, quindi il timer ticchetterà agli intervalli nell'orario sopra.

int CalculateTimerInterval(int minute)
{
    if (minute <= 0)
        minute = 60;
    DateTime now = DateTime.Now;

    DateTime future = now.AddMinutes((minute - (now.Minute % minute))).AddSeconds(now.Second * -1).AddMilliseconds(now.Millisecond * -1);

    TimeSpan interval = future - now;

    return (int)interval.TotalMilliseconds;
}

Questo codice viene utilizzato come segue:

static System.Windows.Forms.Timer t;
const int CHECK_INTERVAL = 20;


static void Main()
{
    t = new System.Windows.Forms.Timer();
    t.Interval = CalculateTimerInterval(CHECK_INTERVAL);
    t.Tick += new EventHandler(t_Tick);
    t.Start();
}

static void t_Tick(object sender, EventArgs e)
{
    t.Interval = CalculateTimerInterval(CHECK_INTERVAL);
}
È stato utile?

Soluzione

System.Timers.Timer . Se vuoi correre in momenti specifici della giornata, dovrai capire quanto tempo ci vorrà fino alla prossima volta e impostarlo come intervallo.

Questa è solo l'idea di base. A seconda di quanto devi essere preciso, puoi fare di più.

int minutes = DateTime.Now.Minute;
int adjust = 10 - (minutes % 10);
timer.Interval = adjust * 60 * 1000;  

Altri suggerimenti

Puoi trovare aiuto su Quartz.net http://quartznet.sourceforge.net/

Ecco un esempio di un sistema leggero che utilizza la sincronizzazione dei thread e una chiamata asincrona.

So che ci sono alcuni aspetti negativi, ma mi piace usare questo invece di un timer quando si avvia un processo a esecuzione prolungata (come i servizi di backend programmati). Dal momento che scorre in linea nel thread del timer, non devi preoccuparti che venga nuovamente avviato prima che la chiamata originale sia terminata. Questo potrebbe essere esteso un po 'per far sì che utilizzi una serie di periodi di dati come tempi di attivazione o aggiunga qualche altra abilità. Sono sicuro che alcuni di voi là fuori conoscono modi migliori.

    public Form1()
    {
        InitializeComponent();

        //some fake data, obviously you would have your own.
        DateTime someStart = DateTime.Now.AddMinutes(1);
        TimeSpan someInterval = TimeSpan.FromMinutes(2);

        //sample call
        StartTimer(someStart,someInterval,doSomething);
    }

    //just a fake function to call
    private bool doSomething()
    {
        DialogResult keepGoing = MessageBox.Show("Hey, I did something! Keep Going?","Something!",MessageBoxButtons.YesNo);
        return (keepGoing == DialogResult.Yes);
    }

    //The following is the actual guts.. and can be transplanted to an actual class.
    private delegate void voidFunc<P1,P2,P3>(P1 p1,P2 p2,P3 p3);
    public void StartTimer(DateTime startTime, TimeSpan interval, Func<bool> action)
    {
        voidFunc<DateTime,TimeSpan,Func<bool>> Timer = TimedThread;
        Timer.BeginInvoke(startTime,interval,action,null,null);
    }

    private void TimedThread(DateTime startTime, TimeSpan interval, Func<bool> action)
    {
        bool keepRunning = true;
        DateTime NextExecute = startTime;
        while(keepRunning)
        {
            if (DateTime.Now > NextExecute)
            {
                keepRunning = action.Invoke();
                NextExecute = NextExecute.Add(interval);
            }
            //could parameterize resolution.
            Thread.Sleep(1000);
        }            
    }

Un'altra strategia per questo sarebbe quella di registrare l'ULTIMA VOLTA che il processo è stato eseguito e determinare se l'intervallo desiderato è trascorso da quel momento. In questa strategia, codificheresti l'evento in modo che si attivi se il tempo trascorso è uguale o maggiore dell'intervallo desiderato. In questo modo è possibile gestire i casi in cui è possibile perdere lunghi intervalli (una volta al giorno, ad esempio) se il computer dovesse essere spento per qualche motivo.

Ad esempio:

  • lastRunDateTime = 5/2/2009 alle 20:00
  • Voglio eseguire il mio processo ogni 24 ore
  • In un evento timer, controlla se sono trascorse 24 ore o PIÙ dall'ultima volta che è stato eseguito il processo.
  • Se sì, esegui il processo, aggiorna lastRunDateTime aggiungendo l'intervallo desiderato (24 ore in questo caso, ma qualunque cosa tu abbia bisogno che sia)

Ovviamente, affinché questo si ripristini dopo che il sistema si è spento, sarà necessario archiviare lastRunDateTime in un file o database da qualche parte in modo che il programma possa riprendere da dove si era interrotto al ripristino.

System.Windows.Forms.Timer (o System.Timers.Timer)

ma poiché ora dici di non voler utilizzare i timer, puoi eseguire un processo di attesa leggero su un altro thread (controlla il tempo, dormi qualche secondo, controlla ancora il tempo ...) o crea un componente che genera un evento (utilizzando un processo di attesa leggero) in determinati orari o intervalli programmati

Il mio obiettivo è quello di eseguire un'importazione intorno alle 03:00 ogni notte.

Ecco il mio approccio, usando System.Timers.Timer:

private Timer _timer;
private Int32 _hours = 0;
private Int32 _runAt = 3;

protected override void OnStart(string[] args)
{
    _hours = (24 - (DateTime.Now.Hour + 1)) + _runAt;
    _timer = new Timer();
    _timer.Interval = _hours * 60 * 60 * 1000;
    _timer.Elapsed += new ElapsedEventHandler(Tick);
    _timer.Start();
}

void Tick(object sender, ElapsedEventArgs e)
{
    if (_hours != 24)
    {
        _hours = 24;
        _timer.Interval = _hours * 60 * 60 * 1000;
    }

    RunImport();
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top