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

WinRT Discussion :

Timer imprécis sous WinRT


Sujet :

WinRT

  1. #1
    Membre averti
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2002
    Messages
    255
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2002
    Messages : 255
    Points : 445
    Points
    445
    Par défaut Timer imprécis sous WinRT
    Bonjour;

    Je travaille sur un jeu comprenant des pendules, mais j'ai remarqué qu'elle est imprécise sous métro alors que le même
    code sous desktop et silverlight fonctionne parfaitement (précision).
    Le timer à environ 1O% d'erreur, par exemple sur 10s il est en retard de 1.5s sur un chrono classique. C'est encore pire dans le simulateur (par
    rapport à l'ordi local) avec un retard de 3.5s sur 10s. En compilant pour le simulateur on voit même à l’œil nu que les dixièmes de secondes
    sont au ralenti.
    Voici le code (un textblock + 2 boutons en xaml):

    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
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
     
    namespace timer
    {
     
        public sealed partial class MainPage : Page
        {
            const string INITTIME = "00:00:10:0";
            const string PENDULE_FORMAT = @"hh\:mm\:ss\:f";
     
            static TimeSpan time = new TimeSpan();
            static readonly TimeSpan DIZIEME_SEC = TimeSpan.FromMilliseconds(100);
            static DispatcherTimer timer = new DispatcherTimer();
     
            public MainPage()
            {
                this.InitializeComponent();
                timer.Tick += timer_Tick;
                timer.Interval = DIZIEME_SEC;
                time = TimeSpan.FromSeconds(10);
                txtblock.Text = INITTIME;
            }
     
            void timer_Tick(object sender, object e)
            {
                time = time.Subtract(DIZIEME_SEC);
                txtblock.Text = time.ToString(PENDULE_FORMAT);
                if (time.TotalMilliseconds <= 0)
                    timer.Stop();
            }
     
            void start_Click(object sender, RoutedEventArgs e)
            {
                txtblock.Text = INITTIME;
                time = TimeSpan.FromSeconds(10);
                timer.Start();
            }
     
           void stop_Click(object sender, RoutedEventArgs e)
            {
                timer.Stop();
            }
        }
    }
    J'utilise vs2012 express pour win8. Bien sûr, je compile en release.
    Peut-être que le DispatcherTimer n'est pas adapté sous métro?
    Merci.

  2. #2
    Membre expert
    Avatar de GuruuMeditation
    Homme Profil pro
    .Net Architect
    Inscrit en
    Octobre 2010
    Messages
    1 705
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : Belgique

    Informations professionnelles :
    Activité : .Net Architect
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2010
    Messages : 1 705
    Points : 3 568
    Points
    3 568
    Par défaut
    En WPF (j'imagine que c'est la même chose sous WinRT) le dispatchertimer garanti juste qu'il ne sera pas appelé avant l'intervalle voulu. Ca dépend du travail sur le dispatcher.

    Alors en Metro c'est peut-être la même chose, mais avec un dispatcher plus encombré, d'où l'imprécision.

    Je n'ai plus le code sous la main et c'était sous WP8 mais j'ai du utiliser un timer pour une app et c'était assez précis
    Microsoft MVP : Windows Platform

    MCPD - Windows Phone Developer
    MCPD - Windows Developer 4

    http://www.guruumeditation.net

    “If debugging is the process of removing bugs, then programming must be the process of putting them in.”
    (Edsger W. Dijkstra)

  3. #3
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Points : 39 749
    Points
    39 749
    Par défaut
    Citation Envoyé par Fabiani Voir le message
    Peut-être que le DispatcherTimer n'est pas adapté sous métro?
    Si tu as besoin d'une bonne précision, il n'est pas adapté tout court (même en WPF ou Silverlight)... Ca peut marcher à peu près correctement si le thread UI n'est pas trop occupé, mais c'est sans garantie. Si tu as besoin d'un timer précis, utilise System.Threading.Timer

  4. #4
    Membre averti
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2002
    Messages
    255
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2002
    Messages : 255
    Points : 445
    Points
    445
    Par défaut
    Bonjour,

    Ok, merci à vous, c'est un peu ce que je pensais mais j'avais aussi un doute sur mon code.

    Salutations.

  5. #5
    Membre averti
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2002
    Messages
    255
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2002
    Messages : 255
    Points : 445
    Points
    445
    Par défaut
    Bonjour,

    Pour ceux que ça intéresse, j'ai finalement utilisé un ThreadPoolTimer, voici la partie principale :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
     
     
    threadPoolTimer = ThreadPoolTimer.CreatePeriodicTimer((source) =>
                {
                   timePool = timePool.Subtract(DIZIEME_SEC);
     
                 //pour modifs UI
                 Dispatcher.RunAsync(CoreDispatcherPriority.High, () => 
                 { 
                    txtblockpool.Text = timePool.ToString(PENDULE_FORMAT); 
                 }).AsTask().Wait();
     
                }, TimeSpan.FromMilliseconds(100));
    La précision est au rendez-vous maintenant.
    Merci.

  6. #6
    Expert confirmé Avatar de DonQuiche
    Inscrit en
    Septembre 2010
    Messages
    2 741
    Détails du profil
    Informations forums :
    Inscription : Septembre 2010
    Messages : 2 741
    Points : 5 485
    Points
    5 485
    Par défaut
    Cette solution foirera de la même façon lorsque le CPU sera débordé, c'est ton approche générale qui est mauvaise.

    Problèmes :
    a) Il faut comprendre que toutes les valeurs communes de temps sous Windows n'ont qu'une précision de 15ms par défaut (Thread.Sleep, DateTime.Now, ThreadPoolTimer, etc) C'est d'ailleurs aussi le cas sous les autres OS : sur Linux la précision par défaut n'est que de 1ms. Si tu as besoin de quelque chose de plus précis, il faut des timers dits "multimédias" ou "haute résolution", comme celui de la classe Stopwatch. Bref, en demandant un tic toutes les 100ms, tes tics réels sont en fait espacés de 90ms parfois et de 105ms d'autres fois. 105, 210, 300, 405, etc. Tu aurais donc toujours au moins 5ms à 10ms d'erreur, même si au final elles tendent à se compenser. Note aussi que sur certains systèmes Windows cette durée peut être plus faible ou plus grande, 15 n'est que la valeur par défaut.

    b) Quand un tic se produit ton code est seulement mis en file. Mais il ne sera exécuté que lorsqu'une tranche CPU sera disponible. Et, en plus, dans ton premier code, tu réclamais spécifiquement une exécution sur le thread UI donc il fallait aussi que celui-ci soit libre. Dans tous les cas il y a une file d'attente, ton code n'est jamais exécuté immédiatement et tu peux avoir plusieurs tics d'affilée à traiter.


    Solutions:
    a) N'incrémente/décrémente pas manuellement une durée à chaque tic. Stocke l'heure de début et calcule dynamiquement à chaque tic la durée écoulée en faisant (DateTime.Now - début). De cette façon tu n'empiles pas les erreurs et tu gères correctement le cas où ton code est resté trop longtemps en file. Attention, note que tu pourrais détecter plusieurs fois la fin et que tu pourrais toujours recevoir des tics après avoir supprimé l'abonnement à ton timer.

    b) SI tu as besoin d'un temps précis pour ajuster les animations entre deux images, 15ms est trop grossier: à 60 ips DateTime.Now varierait de 0ms, 15ms ou 30ms entre deux images, selon les fois. Il te faut donc un timer haute-performances (StopWatch). Tu relèves une fois au début de chaque image la valeur ElapsedMillisecond et tu calcules toutes tes animations en fonction de ce temps. Attention, l'appel à Stopwatch.ElapsedMilliseconds est coûteux.

  7. #7
    Membre averti
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2002
    Messages
    255
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 47
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2002
    Messages : 255
    Points : 445
    Points
    445
    Par défaut
    DonQuiche,

    J'ai hésité avec StopWatch, mais comme "de visu" ça parait plus précis j'ai opté pour un ThreadPoolTimer.
    Comme tu le précises la fourchette peut tomber au dessus ou en dessous donc ça compense au final c'est
    pour ça que ça "parait" correct.
    Merci pour tes précisions car en général je suis assez pointilleux mais là j'ai déjà pris du retard donc j'ai un peu
    laissé les détails, mais je vais prendre un peu de temps pour tester StopWatch.
    Merci encore.

    Salutations.

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

Discussions similaires

  1. Jeu saccadé: Timer ? Thread? sous python.
    Par pagugu dans le forum Programmation multimédia/Jeux
    Réponses: 6
    Dernier message: 18/04/2010, 16h50
  2. Timer sous linux
    Par Ikit dans le forum Linux
    Réponses: 13
    Dernier message: 09/02/2010, 16h34
  3. Faire un timer precis sous windows !
    Par Niklaos dans le forum C++
    Réponses: 4
    Dernier message: 06/01/2010, 22h15
  4. Interruption Timer sous Borland C
    Par Spacy_green dans le forum C
    Réponses: 3
    Dernier message: 20/06/2006, 23h40
  5. timer sous linux
    Par t-ma&&& dans le forum Linux
    Réponses: 1
    Dernier message: 08/04/2006, 12h06

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