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

Delphi Discussion :

Précision de GetTickCount


Sujet :

Delphi

  1. #1
    Membre habitué
    Homme Profil pro
    Développeur Delphi
    Inscrit en
    Juin 2017
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur Delphi

    Informations forums :
    Inscription : Juin 2017
    Messages : 8
    Par défaut Précision de GetTickCount
    Bonjour à tous et à toutes.

    Je suis sur un problème un peu énervant que j'aimerais vous faire partager. Il n'y a pas de raison que je sois le seul à être énervé un vendredi .

    Je suis dans l'exécution d'un thread que je veux répéter toutes les secondes (en tenant compte du temps de traitement, cela va sans dire).
    Je code donc :

    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
     
     
      while not Terminated do
        begin
          StartTime := GetTickCount;    //début des manoeuvres
     
          Mon traitement;
          Synchronize('MonInterface');
     
          //  ElapsedTime := (1000 - (GetTickCount - StartTime));   //Je décompte le temps de traitement (GetTickCount - StartTime) de ma seconde
          //Sleep(ElapsedTime);                                                    //j'attends le temps nécessaire 
                                                                                             //OU (j'ai dépensé mon temps sans compter)
          while GetTickCount < (StartTime + 1000) do                  //je boucle tant que je ne suis pas arrivé à tps de traitement + ma seconde
            begin
            end;
        end;
    Le problème est que, après avoir essayé des trucs que j'ai trop honte de vous rapporter, j'arrive toujours à une différence de 13 ou 14 milisecondes , des fois un peu plus, un peu moins, mais rarement.
    Quelqu'un pourrait-il m'expliquer pouquoi ?

    Merci d'avance.

  2. #2
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 912
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 912
    Par défaut
    C'est normal, GetTickCount se base sur le clock système qui survient toutes les N millisecondes (environ 12 ms de mémoire). Il faut passer par un compteur de précision :
    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
    function GetTickCountEx :Extended;
    var
      Frequency :Int64;
      Counter   :Int64;
     
    begin
      //Si le compteur de précision n'est pas disponible
      //utilise GetTickCount converti en seconde.
      if QueryPerformanceFrequency(Frequency) then
      begin
        QueryPerformanceCounter(Counter);
        Result := Counter /Frequency;
      end
      else Result := GetTickCount *1000;
    end;
    Cela dit, lancer une boucle d'attente va bloquer un cœur du CPU pour cette seule tâche. Tu pénalises le système global.
    Sleep de son côté va rendre la main mais sans savoir exactement quand il pourra la récupérer (plus la priorité du processus/thread sera haute, plus ce sera rapide).

    Pas sûr que tu arrives à tes fins...

  3. #3
    Membre habitué
    Homme Profil pro
    Développeur Delphi
    Inscrit en
    Juin 2017
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur Delphi

    Informations forums :
    Inscription : Juin 2017
    Messages : 8
    Par défaut
    Bonjour et merci pour ton aide Andnotor.

    Tu m'as donné le principal, l'explication du pourquoi.
    Néanmoins, j'ai essayé d'appliquer ton exemple, mais j'arrive à des écarts bien plus importants.
    Suivant ton conseil, j'ai préféré remettre Sleep(ElapsedTime);
    Pour le reste, j'ai gardé GetTickCount qui me met 12 ms (en fait, j'ai des différences de 13 ou 14 le plus souvent) dans les dents à chaque boucle de thread. Ce qui est très acceptable sur une boucle de 1 s, à condition que je sache pourquoi .

    Merci encore et bon WE

  4. #4
    Expert éminent
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    14 001
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 14 001
    Par défaut
    Tu peux aussi utiliser un TEvent qui a un délai de 1s !

    Voici le corps de la méthode Execute du TThread.
    Dans ton cas, tu n'exploites que le wrTimeout mais le wrSignaled peut être utilisé pour gérer le Terminate.

    De plus, si ton traitement dure moins longtemps que le délai et que tu veux garantir une exécution toutes les secondes,
    tu affectes à FDelay 1s - temps de traitement et donc c'est pas Sleep(ElapsedTime); mais Sleep(1000 - ElapsedTime).

    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
       while not Terminated do
      begin
        wr := FSignal.WaitFor(FDelay);
        case wr of
          wrSignaled:
            begin
              // Si l'on arrête le Batch, on ne traite pas les fichiers
              if not Terminated then
                Process();
            end;
          wrTimeout:
            begin
              // Si l'on arrête le Batch, on ne se préoccupe plus de l'inactivité !
              if not Terminated then
                Idle();
            end;
        end;
      end;
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    //------------------------------------------------------------------------------
    procedure TAutomateLogistiqueSDIFileProcessor.TerminatedSet();
    begin
      inherited TerminatedSet();
     
      if Assigned(FSignal) then
        FSignal.SetEvent(); // Arrêt prématuré !
    end;
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

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

Discussions similaires

  1. [Nelrina] Bonjour à tous et à toutes !
    Par Nelrina dans le forum Présentations
    Réponses: 4
    Dernier message: 23/12/2015, 22h15
  2. [Fagulf] Bonjour à tous et toutes
    Par Fagulf dans le forum Présentations
    Réponses: 1
    Dernier message: 08/02/2013, 16h13
  3. [IL-MAFIOSO] Bonjour à tous et toutes
    Par IL-MAFIOSO dans le forum Présentations
    Réponses: 1
    Dernier message: 19/03/2012, 11h47
  4. [balderounet] Bonjour à tous et à toutes
    Par balderounet dans le forum Présentations
    Réponses: 2
    Dernier message: 03/05/2011, 13h00
  5. Bonjour à tous...
    Par Soleil1484 dans le forum Balisage (X)HTML et validation W3C
    Réponses: 17
    Dernier message: 13/12/2005, 11h25

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