IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C# Discussion :

[TIMER WPF] Intervale précise


Sujet :

C#

  1. #1
    Membre averti Avatar de megamario
    Homme Profil pro
    VB6/VB.net/C/C++/C#
    Inscrit en
    Septembre 2008
    Messages
    929
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Indre et Loire (Centre)

    Informations professionnelles :
    Activité : VB6/VB.net/C/C++/C#
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2008
    Messages : 929
    Points : 312
    Points
    312
    Par défaut [TIMER WPF] Intervale précise
    Bonjour à tous,

    Décidément je n'arrête pas en ce moment de vous solliciter.

    J'ai un petit souci avec les Timer de mon programme en WPF.
    Le client à besoin d'écrire un rapport des mesures effectuées toutes les X minutes dans un fichiers en local et sur un serveur sftp.

    Le souci c'est que s'il règle le Timer à 1 minutes, il veux qu'après 24h il a 1440 fichiers.

    Vu comme sa pas de souci, mais un dispatcherTimer, apparemment, commence à recompter après la sortie de l'évènement. Sur une journée, entre l'écriture des fichiers et l'envoie vers le SFTP j'ai un décalage, léger certes, mais j'ai pas les 1440 fichiers.

    Pour m'affranchir du temps de traitement d'écriture et envoie, dans l'évènement tick du timer je créé uniquement un BackgroundWorker, et c'est lui qui gère ensuite les fichiers.
    Malgré cela j'ai un petit décalage dans le temps, d'une seconde sur une 15 éne de fichiers (donc 1 secondes toutes les 15 minutes).

    Comment gérer cela pour être toujours parfaitement caller à la seconde prêts ? et avoir mes 1440 fichiers en 24H.

    Ralentir le temps c'est facile en ajoutant un sleep, mais l'accélérer ??


    Justement, en parlant de ralentir le temps, j'ai fait un test:

    Lors de la déclaration de mon Timer, j'ai enlevé 200 millisecondes sur l'intervalle.
    Et j'initialise un DateTime de réference.

    Puis je fait cela:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
     
      private void bdtTimer_Tick(Object sender, EventArgs ev)
            {
                //TimeRéf est initialisé lors du démarrage du timer
                //BaseDeTempsMS est le délais entre chaque écriture.
                //Calcul du temps manquant (200ms étant déduit de BaseDeTempsMS lors de la déclaration du timer)
                TimeSpan Diff =  (DateTime.Now - TimeRef) ;
                int millisec = BaseDeTempsMS - (int)Diff.TotalMilliseconds;
                //Si il manque du temps je fait une pause de ce temps.
                if (millisec > 0)
                {
                        System.Threading.Thread.Sleep(millisec);       
                }
                //J'ajoute au temps de référence, la valeur de l'intervalle réel souhaité.
                TimeRef = TimeRef.AddMilliseconds(BaseDeTempsMS) ;
     
     
                BackgroundWorker worker = new BackgroundWorker();
                worker.DoWork += worker_DoWork;
                worker.RunWorkerCompleted += worker_RunWorkerCompleted;
                //Je passe au BackgroundWorker le temps réel afin de l'écrire dans le nom du fichier et voir sont évolution.
                worker.RunWorkerAsync(DateTime.Now);
     
            }
    Conclusion:
    Avec ce code, en réglant le timer à 1 minutes, j'ai un petit écart entre les fichiers, mais cela se stabilise toujours autour des mêmes valeurs en ms. On a bien la même minute +1 à chaque fois et les mms oscille entre 325 et 385, je pourrais essayé de les caller vers les 500 ms afin de ne jamais basculer d'une seconde..

    Cela fonctionne donc, mais c'est quand même de la bidouille. Si vous avez d'autre suggestion je suis preneur, merci.

  2. #2
    Expert éminent sénior Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 154
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 154
    Points : 25 072
    Points
    25 072
    Par défaut
    ne pas utiliser de timer, démarrer un thread (ou utiliser le backgroundworker qui en démarre un)
    dans le thread (ou l'event du bgw) faire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    while (true)
    {
      if (c'est l'heure de générer un fichier) GenereFichier();
      System.Threading.Thread.Sleep(500);
    }
    là tu seras à moins d'une seconde de décalage par heure.
    Tu peux baisser (il faut au moins un sleep(1) sinon l'appli va prendre 100% du processeur, au dessus 10 ca ne pose aucun problème à priori)
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  3. #3
    Membre averti Avatar de megamario
    Homme Profil pro
    VB6/VB.net/C/C++/C#
    Inscrit en
    Septembre 2008
    Messages
    929
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Indre et Loire (Centre)

    Informations professionnelles :
    Activité : VB6/VB.net/C/C++/C#
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2008
    Messages : 929
    Points : 312
    Points
    312
    Par défaut
    Citation Envoyé par Pol63 Voir le message
    ne pas utiliser de timer, démarrer un thread (ou utiliser le backgroundworker qui en démarre un)
    dans le thread (ou l'event du bgw) faire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    while (true)
    {
      if (c'est l'heure de générer un fichier) GenereFichier();
      System.Threading.Thread.Sleep(500);
    }
    là tu seras à moins d'une seconde de décalage par heure.
    Tu peux baisser (il faut au moins un sleep(1) sinon l'appli va prendre 100% du processeur, au dessus 10 ca ne pose aucun problème à priori)
    Bonjour Pol63,

    Houaiiii, mon client veux 0 secondes à la journée , c'est pas de con.. bêtise pardon. Il veux ces 1440 fichiers à la journée.

    Pour le moment je vais rester comme cela, de toutes manière j'ai des corrections "rapide" à faire pour lui envoyer et j'ai d'autre problème qui vont me prendre plus de temps, je pourrais corriger ensuite.
    Actuellement avec ma correction permanente j'ai + ou - 3 ms entre chaque fichiers, que j'ai callé autour des 500ms pour jamais avoir une seconde d'écart.
    pour mon DateTime de référence je l'ai callé donc avec 500ms

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     TimeRef = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, DateTime.Now.Hour, DateTime.Now.Minute, DateTime.Now.Second,500) ;

  4. #4
    Membre averti Avatar de megamario
    Homme Profil pro
    VB6/VB.net/C/C++/C#
    Inscrit en
    Septembre 2008
    Messages
    929
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Indre et Loire (Centre)

    Informations professionnelles :
    Activité : VB6/VB.net/C/C++/C#
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2008
    Messages : 929
    Points : 312
    Points
    312
    Par défaut
    Citation Envoyé par Pol63 Voir le message
    ne pas utiliser de timer, démarrer un thread (ou utiliser le backgroundworker qui en démarre un)
    dans le thread (ou l'event du bgw) faire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    while (true)
    {
      if (c'est l'heure de générer un fichier) GenereFichier();
      System.Threading.Thread.Sleep(500);
    }
    là tu seras à moins d'une seconde de décalage par heure.
    Tu peux baisser (il faut au moins un sleep(1) sinon l'appli va prendre 100% du processeur, au dessus 10 ca ne pose aucun problème à priori)


    Bonjour Pol63,

    J'ai malgré tout suivi ton conseil, merci.

    Il faut vraiment se méfier des Timer. En l'occurrence les DispatcherTimer, Ils ne sont pas complètement indépendant et reste lié au thread qui les à créés. Les interruptions d'erreur comme un serveur SFTP qui ne répond pas par exemple, bloque le logiciel malgré qu'il soit dans l'évènement tick de ce Timer.
    J'ai constaté aussi que les Thread.Sleep() ne sont pas non plus parfait. Lorsque je les intègres dans une boucle j'ai constaté une dérive assez significative (dans mon cas).

    Ce que j'ai fait:

    Comme le préconise Pol je ne suis plus passé par des Timer, mais une boucle dans un thread:

    Code pas encore parfait avec encore de la dérive:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
     
    while (true)
                    {
                        //Une pause suivant la base de temps ou j'ai réduit 3 secondes
                        Thread.Sleep(BaseDeTempsMS - 3000);
     
                        //calcule du temps manquant (normalement 3 secondes mais c'est rarement 3 secondes pile)
                        TimeSpan Diff = (DateTime.Now - TimeRef);
                        int millisec = BaseDeTempsMS - (int)Diff.TotalMilliseconds;
                        //S'il me manque du temps j'attends dans cette boucle
                        if (millisec > 0)
                        {
                            for (long i = 0; i < millisec; i = i + 10)
                            {
                                System.Threading.Thread.Sleep(10);
                            }
                        }
                        //J'ajoute a mon Temps de réference la base de temps du "Timer"
                        TimeRef = TimeRef.AddMilliseconds(BaseDeTempsMS);
                        //traitement des fichiers
                        PoolWriteFile();
     
                    }
    Bon cela ne marchait pas trop mal lorsque je soustrait uniquement 100ms de ma BaseDeTempsMS , mais avec 3 secondes la dérive était fréquente et je le rappelle j'ai besoin de la totalité des mes fichiers 1440 fichiers sur la journée si j'ai une BaseDeTempsMS de 1 minutes,

    Ensuite j'ai donc modifié cela pour corriger en permanence et la nickel.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
     
                    //DateTime TimeRef est initialisé à l'heure actuel en forçant les ms à 500.
     
                    TimeRef = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, DateTime.Now.Hour, DateTime.Now.Minute, DateTime.Now.Second, 500);
                    while (true)
                    {
                        int millisec;
                        do
                        {
                            System.Threading.Thread.Sleep(100);
                            //Je vérifie à chaque tour suivant la date et l'heure en cours pour éviter les dérives
                            TimeSpan Diff = (DateTime.Now - TimeRef);
                            millisec = BaseDeTempsMS - (int)Diff.TotalMilliseconds;
     
                        } while (millisec > 0);
                        TimeRef = TimeRef.AddMilliseconds(BaseDeTempsMS);
                        //traitement des fichiers
                        PoolWriteFile();
     
                    }
    Pour l'écriture des fichiers en local dans PoolWriteFile() je lance un BackgroundWorker.

    Et pour l'envoie des fichiers en SFTP j'ai de nouveau un thread avec une boucle qui surveille s'il y a des fichiers présents, une fois envoyés il les déplace dans un répertoire correspondant à la date du fichier, ainsi même si le SFTP ne répond pas, je n'ai plus de blocage, les fichiers seront écrit en local puis envoyé quand le SFTP sera disponible.

    Je ne m'attendais pas à sa, la dérive des timer, et la dérive d'un sleep.


    Merci Pol63, aussi en passant par un thread je n'est plus de blocage si le SFTP à un souci, ma vue reste active et fluide si besoin.

  5. #5
    Expert éminent sénior

    Avatar de François DORIN
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Juillet 2016
    Messages
    2 757
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2016
    Messages : 2 757
    Points : 10 541
    Points
    10 541
    Billets dans le blog
    21
    Par défaut
    Je viens après la bataille, mais j'avais écris un article sur l'implémentation de tâches périodiques : https://fdorin.developpez.com/tutori...eadpool/part4/
    François DORIN
    Consultant informatique : conception, modélisation, développement (C#/.Net et SQL Server)
    Site internet | Profils Viadéo & LinkedIn
    ---------
    Page de cours : fdorin.developpez.com
    ---------
    N'oubliez pas de consulter la FAQ C# ainsi que les cours et tutoriels

  6. #6
    Membre averti Avatar de megamario
    Homme Profil pro
    VB6/VB.net/C/C++/C#
    Inscrit en
    Septembre 2008
    Messages
    929
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : France, Indre et Loire (Centre)

    Informations professionnelles :
    Activité : VB6/VB.net/C/C++/C#
    Secteur : Industrie

    Informations forums :
    Inscription : Septembre 2008
    Messages : 929
    Points : 312
    Points
    312
    Par défaut
    Citation Envoyé par François DORIN Voir le message
    Je viens après la bataille, mais j'avais écris un article sur l'implémentation de tâches périodiques : https://fdorin.developpez.com/tutori...eadpool/part4/
    Bonjour, pas de souci c'est toujours bon à prendre. Je vais regarder cela dès que possible(réunion).

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Timer et intervalle
    Par ugo188 dans le forum GTK+ avec C & C++
    Réponses: 5
    Dernier message: 29/04/2009, 23h54
  2. Timer et Intervalles
    Par remsrock dans le forum C#
    Réponses: 3
    Dernier message: 18/09/2008, 12h03
  3. limite de l'intervalle du controle timer
    Par louzar dans le forum VB 6 et antérieur
    Réponses: 1
    Dernier message: 20/07/2007, 11h13
  4. [.NET 3-WPF]Insertion d'un timer
    Par sarapis dans le forum Windows Presentation Foundation
    Réponses: 5
    Dernier message: 15/05/2007, 21h15
  5. [Timer]Comment mesurer un intervalle de temps ?
    Par Pill_S dans le forum Collection et Stream
    Réponses: 3
    Dernier message: 07/05/2004, 17h39

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo