9
votes

Déclencher un événement chaque seconde

J'ai une application qui doit vérifier un flux de site Web chaque seconde.

Parfois, la demande au serveur est plus longue qu'une seconde. Dans ce cas, l'application doit attendre jusqu'à la première demande terminée, puis commencer une nouvelle demande immédiatement. Comment pourrais-je mettre en œuvre cela?

En outre, la demande ne doit pas geler l'interface graphique.


3 commentaires

Juste une pensée, mais s'il s'agit d'un site Web public, ce que vous suggérez des fronçons très malgré beaucoup. Frapper un site Web chaque seconde est beaucoup de trafic supplémentaire.


Pour votre interface graphique de ne pas geler, vous aurez certainement besoin d'examiner le filetage. Peut-être qu'un travailleur d'arrière-plan ferait le tour.


En fait, je demande au site Web API. Ils permettent de faire des demandes à leur API autant qu'une fois une seconde.


7 Réponses :


1
votes

Un objet de minuterie peut faire le tour pour vous. Vous pouvez la définir pour tirer chaque seconde. Le code qui s'exécute sur la tirée de la minuterie désactiverait d'abord la minuterie, faire son travail et réactive la minuterie. En désactivant la minuterie, il ne tiendra pas à nouveau, jusqu'à ce qu'il ne soit fait de traitement.


1 commentaires

Si la demande de site Web durer plus de seconde, après la demande complète de la demande attendra une seconde avant d'envoyer une nouvelle demande, mais j'en ai besoin pour envoyer une nouvelle demande immédiatement



4
votes

Je serais enclin à utiliser un thread séparé comme celui-ci: xxx

Dispatcher.invoke Transitions sur le thread utilisateur pour la mise à jour de l'interface utilisateur réelle. Cela implémente le consommateur producteur très efficacement.

the thread.isbackground = true provoque l'arrêt du thread lorsque votre application se termine. Si vous voulez qu'il s'arrête plus tôt que cela, définissez une valeur «stop» sur «vrai». La valeur "Stop" dans le code ci-dessus est supposée être une propriété Bool de la classe, mais elle pourrait être quelque chose - même une variable locale.


2 commentaires

Oui, je pense que cela fonctionnera. J'ai une autre question, si j'ai plus d'un site à vérifier (par exemple 10). Et je veux aller chercher de l'essai d'eux en parallèle. Je devrai commencer un nouveau fil pour chaque site? Est-ce une bonne idée?


S'il n'y a que 10 sites, je collerais avec cette solution et commencer à démarrer 10 threads. S'il y a 100 sites, j'utiliserais webrequest.begingreesponse et iAsyncResult à la place. Mais assurez-vous que votre tuyau entrant est assez gros pour que vous ne commenciez pas les paquets.



8
votes

J'utiliserais une simple variation du modèle de producteur-consommateur. Vous auriez deux THEADS, un producteur et un consommateur, qui partagent une variable entière. Le producteur aurait un system.threading.threading.Timer code> qui a tiré chaque seconde, à quelle heure il serait interlocked.incrimement code> la variable et appelez le consommateur. La logique des consommateurs vérifie à plusieurs reprises le flux et interlocked.decrement code> le compteur, tandis que le compteur est supérieur à zéro. La logique de consommation serait protégée par un moniteur.justeur code> qui gérerait la réintensif. Voici un exemple de code.

FeedCheck.Start();


2 commentaires

Au fait, bienvenue à Stackoverflow. N'oubliez pas de voter de manière utile que vous trouvez utile.


Merci. Votre réponse était très utile. Je ne peux pas voter jusqu'à ce que je n'ai 15 pas de réputation :(



0
votes

Vous pouvez essayer de créer une application principale qui contiendrait l'interface graphique que vous ne voudriez pas geler. Il commencerait un fil avec une boucle qui irait itérale après une durée spécifique. Si la minuterie est égale / dépasse le temps défini, démarrez un autre thread pour la demande. Mais vérifiez si un fil existe déjà avant de commencer. Sinon, alors bloquer l'exécution jusqu'à ce que le fil de la demande soit terminé. E.G.:

Main
{
    Create gui;
    Start loop thread;
}

Loop thread
{
    loop while not exit
    {
        timer();
        WaitForResource()
        start RequestThread
    }
}

RequestThread
{
    Lock resource/semaphore
    Request, Update GUI
    free semaphore
}

REPARTEMENT: Ne le faites pas chaque seconde. Comme les autres affiches l'ont dit, il est un peu irrespectueux envers les propriétaires de sites. Vous risquez de vous faire refuser l'accès au flux par les propriétaires de sites Web. P> p>


0 commentaires

1
votes

Utilisez une minuterie comme ceci:

    System.Timers.Timer timer = new System.Timers.Timer(1000);

    public void StartTimer()
    {
        timer.Elapsed += new System.Timers.ElapsedEventHandler(this.TimerHandler);
        timer.Start();
    }

    private void TimerHandler(object sender, System.Timers.ElapsedEventArgs e)
    {
        DateTime start;
        TimeSpan elapsed = TimeSpan.MaxValue;

        timer.Stop();

        while (elapsed.TotalSeconds > 1.0)
        {
            start = DateTime.Now;

            // check your website here

            elapsed = DateTime.Now - start;
        }
        timer.Interval = 1000 - elapsed.TotalMilliseconds;
        timer.Start();
    }


2 commentaires

Cela ne doit-il pas attendre 1 seconde après que la demande soit complète au lieu de tirer immédiatement si la demande était supérieure à 1 seconde?


@CCCTRASH: OOPS - J'ai mal interprété votre question. J'ai édité la minuterie pour vérifier à plusieurs reprises jusqu'à ce que le temps écoulé tombe en dessous d'une seconde, puis ajustez la minuterie pour tirer une seconde après la dernière minuterie.



0
votes

Je pense que ce moyen le plus simple de traiter cela est maintenant d'utiliser le cadre Microsoft réactif (RX).

Ainsi, en supposant que j'ai une fonction qui appellera le site Web Flight et renvoyera une réponse Objet, comme celui-ci: xxx

puis je peux simplement faire cela pour le filer: xxx

< Code> CheckwebSiteSiteFeed est appelé sur un thread de fond et le S'inscrire est exécuté sur le fil de l'interface utilisateur. Super simple!


0 commentaires

0
votes

Utilisez une minuterie comme ceci:

System.Timers.Timer timer = new System.Timers.Timer(1000);

public void StartTimer()
{
    timer.Elapsed += new System.Timers.ElapsedEventHandler(this.TimerHandler);
    timer.Start();
}

private void TimerHandler(object sender, System.Timers.ElapsedEventArgs e)
{
    DateTime start;
    TimeSpan elapsed = TimeSpan.MaxValue;

    timer.Stop();

    while (elapsed.TotalSeconds > 1.0)
    {
        start = DateTime.Now;

        // check your website here

        elapsed = DateTime.Now - start;
    }
    timer.Interval = 1000 - elapsed.TotalMilliseconds;
    timer.Start();
}


0 commentaires