Partage
  • Partager sur Facebook
  • Partager sur Twitter

Comportement de sleep

Sujet résolu
    27 avril 2019 à 17:02:40

    Hello,

    Est-ce que quelqu'un aurait une explication sur le fonctionnement de sleep au-delà du fait qu'il "pause" le thread actuel pour x secondes. Dans un programme tout ce qu'il y a de plus basique (je rand puis je match un array d'int générée aléatoirement), si je retire le sleep de ma boucle while, le nombre d'essais s'envole (ce qui est normal) par contre si je mets un sleep de 1s j'ai l'impression qu'il met à peu pres le même temps pour matcher en seulement quelques essais, comment est-ce possible ? Est-ce qu'il y a un travail en fond qui persiste même pendant le sleep ?

    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <time.h>
    #include <ctype.h>
    
    #define MAX_SIZE 100
    #define MIN_SIZE 1
    
    void clStream(FILE *in)
    {
        int ch;
        clearerr(in);
    
        do
        {
            ch = getc(in);
        } while ( ch != '\n' && ch != EOF );
    
        clearerr(in);
    }
    
    int main()
    {
        time_t letemps;
        time_t tempsle;
        unsigned int* pSecretNums;
        unsigned int* pNumsFound;
        unsigned int* pFoundSecrets;
        unsigned int found, i, k, listSize, tries;
        unsigned long int startTime;
    
        pSecretNums = pNumsFound = pFoundSecrets = NULL;
        found = i = k = listSize = tries = startTime = 0;
        srand((unsigned int)time(&letemps));
        
        do {
            listSize = 0;
            printf("How many digits are you looking for (from %d to %d included) ?: ", MIN_SIZE, MAX_SIZE);
            fflush(stdout);
            scanf("%d", &listSize);
            clStream(stdin);
        } while ( (int)listSize > MAX_SIZE || (int)listSize < MIN_SIZE );
        
        pSecretNums = (unsigned int *) malloc(listSize * sizeof(unsigned int));
        pFoundSecrets = (unsigned int *) malloc(listSize * sizeof(unsigned int));
        pNumsFound = (unsigned int *) malloc(listSize * sizeof(unsigned int));
        if (!pSecretNums || !pNumsFound || !pFoundSecrets)
        {
            free(pSecretNums);
            free(pNumsFound);
            free(pFoundSecrets);
            exit(1);
        }
        
        printf("\n\n::Generating secret numbers...");
        
        for (i = 0; i < listSize; i++)
        {
            pSecretNums[i] = (rand() % MAX_SIZE) + 1;
            if (pSecretNums[i] < MIN_SIZE || pSecretNums[i] > MAX_SIZE) i--;
        }
        
        printf("\n::Start looking for secret numbers...");
        startTime = time(&letemps);
    
        while (!found)
        {
            srand((unsigned int)time(&letemps));
            
            for (i = 0; i < listSize; i++)
                pNumsFound[i] = (rand() % MAX_SIZE) + 1;
            
            for (i = 0; i < listSize; i++)
            {
                for (k = 0; k < listSize; k++)
                {
                    if (pNumsFound[k] == pSecretNums[i])
                        pFoundSecrets[i] = pNumsFound[k];
                }
            }
            
            printf("\n::Checking results [%d]...\n", tries+1);
            
            for (i = 0; i < listSize; i++)
            {
                printf("\tindex %d: %d -> %d", i, pFoundSecrets[i], pSecretNums[i]);
                if (pFoundSecrets[i] == pSecretNums[i])
                {
                    found = 1;
                    printf(" match!\n");
                    continue;
                } else {
                    printf(" no match!\n");
                    found = 0;
                    break;
                }
            }
            
            tries++;
            sleep(1);
        }
    
        printf("\n::Generated secret array\n");
    
        for (i = 0; i < listSize; i++)
        {
            printf("%d ", pSecretNums[i]);
        }
        
        printf("\n::Found numbers array\n");
    
        for (i = 0; i < listSize; i++)
        {
            printf("%d ", pFoundSecrets[i]);
        }
    
        printf("\n\n::Found secrets in %d tries!", tries);
        printf("\n::Finished time: %.1fs\n\n", difftime(time(&tempsle), startTime));
        free(pSecretNums);
        free(pFoundSecrets);
        free(pNumsFound);
        
        return 0;
    }

    Output:

    // Sans sleep
    ::Found secrets in 88463 tries!
    ::Finished time: 3.0s
    
    //Avec sleep
    ::Found secrets in 5 tries!
    ::Finished time: 5.0s

    -
    Edité par xoxotf 27 avril 2019 à 17:32:33

    • Partager sur Facebook
    • Partager sur Twitter
      28 avril 2019 à 12:14:32

      Salut,

      Le problème ne vient pas de sleep mais de cette ligne là :

              srand((unsigned int)time(&letemps));

      Un petit mot sur les générateurs aléatoires : le vrai aléatoire n'existe pas dans une machine, à la place, on doit utiliser ce qu'on appelle des générateurs pseudo-aléatoires (PRNG en anglais). Le principe est le suivant : tu pars d'une seed qui est un certain entier, puis à chaque appel successif de rand() tu fais quelque chose ressemblant à : nouveau entier = (ancien entier * a + b) mod N, où a b et N sont bien choisis.

      Seulement il te faut bien choisir un "premier entier" : c'est la fonction srand() qui va te faire ça, en y mettant l'entier de seed directement. (c'est à dire que tu peux faire srand(2) par exemple pour mettre le premier seed à 2)

      Si tu mets srand(time(&x)), ça va : 1) mesurer le temps de l'horloge interne, et 2) mettre le résultat dans x, et aussi 3) retourner ce temps là.

      En répétant srand(time(...)) à chaque tour de boucle, tu réinitialises en fait le générateur aléatoire par rapport au temps écoulé à chaque fois. ça veut dire que le comportement de ton programme (plus précisément, les valeurs aléatoires choisies par rand() ) dépend alors du temps d'exécution de ta boucle. En mettant un sleep(1) dans ta boucle, tu modifies ce temps là - d'où le fait que tu obtiennes des résultats différents avec ou sans sleep.

      Ici, mettre un sleep() t'as permis d'être "plus chanceux" - mais ça aurait pu être l'inverse. J'avoue que 5 essais au lieu de 20000 c'est assez impressionnant par contre, il y a peut-être d'autres bugs ou comportement bizarres qui se cachent dans ton code. Mais si tu mets srand() au tout début de ton programme au lieu de le réinitialiser à chaque fois, tu ne devrais plus avoir ce comportement de la fonction sleep qui altère la génération aléatoire.

      Si tu veux juste mesurer le temps sans réinitialiser le générateur aléatoire : un simple time(&letemps) suffit :)

      -
      Edité par potterman28wxcv 28 avril 2019 à 12:15:53

      • Partager sur Facebook
      • Partager sur Twitter
        28 avril 2019 à 12:42:34

        Salut, merci de ta réponse. J'étais à peu après aux faits par rapport à rand, effectivement dans l'absolu ce que je voulais c'était vraiment m'assurer que mon seed soit modifié à chaque tour pour être plus ou moins sure que j'obtiens un pseudo-aléatoire, j'obtiens trop de doublons en modifiant le seed uniquement en début de programme (enfin j'avais l'impression en tout cas).

        A vrai dire c'est plus l'histoire des essais qui m'a amené à poster sur le forum :p, je ne comprends pas une telle différence d'essais... je ne considère pas que ça soit un bug ou autres, je cherche juste une explication car c'est bien trop flou pour ma part.

        • Partager sur Facebook
        • Partager sur Twitter
          28 avril 2019 à 13:12:21

          xoxotf a écrit:

          Salut, merci de ta réponse. J'étais à peu après aux faits par rapport à rand, effectivement dans l'absolu ce que je voulais c'était vraiment m'assurer que mon seed soit modifié à chaque tour pour être plus ou moins sure que j'obtiens un pseudo-aléatoire, j'obtiens trop de doublons en modifiant le seed uniquement en début de programme (enfin j'avais l'impression en tout cas).

          A vrai dire c'est plus l'histoire des essais qui m'a amené à poster sur le forum :p, je ne comprends pas une telle différence d'essais... je ne considère pas que ça soit un bug ou autres, je cherche juste une explication car c'est bien trop flou pour ma part.

          Je ne sais pas ce que t'appelles par "doublon", mais tu n'as que 100 valeurs possibles dans ton choix aléatoire. Ce n'est pas beaucoup. A la première itération tu as 0 chance de tomber sur un doublon. A la deuxième itération, tu as 1 chance sur 100, à la troisième 2 chances sur 100, etc..

          Si je génère un seul nombre aléatoire entre 1 et 100 à chaque itération, la probabilité de tomber sur un doublon au bout de 10 itérations est : (1 - 99/100 * 98/100 * ... * 91/100) = 37% de chances ! C'est énorme, et ça na rien à voir avec la façon dont l'aléatoire est généré - c'est juste les probabilités qui sont comme ça.

          Sinon, à ta question, c'est encore srand qui est fautif. Parce que quand tu mets time(..), ça te renvoie le temps en secondes

          Si tu mets sleep à chaque tour de boucle, tu es assuré que au moins une seconde se passe dans ta boucle. Donc tu es assuré que srand va réinitialiser à une seed différente à chaque fois.

          Si tu ne mets pas de sleep, la boucle va tourner 88000 fois en réinitialisant à chaque fois la seed à la même valeur, parce que le temps d'exécution de ta boucle est très largement inférieur à 1 seconde. Tu fais donc 88000 tours de boucles pour rien. Tu peux checker ça en mettant un print sur on va dire les 10 premières itérations : tu verras que tu testes exactement les mêmes valeurs si tu mets pas le sleep. D'où la raison pour laquelle il ne trouve pas tes valeurs suffisamment vite.

          -
          Edité par potterman28wxcv 28 avril 2019 à 13:15:29

          • Partager sur Facebook
          • Partager sur Twitter
            28 avril 2019 à 16:29:30

            Je vois! Quand je parle de doublons c'est quand rand me génère deux fois à la suite la même valeur dans mon tableau, je ne cherche pas à avoir un tableau avec des valeurs uniques bien évidemment !

            Je me suis donc trompé sur time(), je pensais que ça renvoyer le temps unix en ms (voir plus bas encore)... et effectivement j'avais déjà observé ce comportement où il teste la même valeur sur différents essais, du coup c'est bien lié avec time().

            Ça devient clair, je comprends la source de ce résultat, merci :). Ça aurait dû être évident en plus, étant donné que j'utilise difftime à la fin pour obtenir mon temps en secondes mais sur le moment j'ai dû me dire que cette méthode faisait un calcul plus poussé en interne...

            -
            Edité par xoxotf 28 avril 2019 à 16:32:18

            • Partager sur Facebook
            • Partager sur Twitter
              28 avril 2019 à 16:44:31

              xoxotf a écrit:

              Je vois! Quand je parle de doublons c'est quand rand me génère deux fois à la suite la même valeur dans mon tableau, je ne cherche pas à avoir un tableau avec des valeurs uniques bien évidemment !

              Je me suis donc trompé sur time(), je pensais que ça renvoyer le temps unix en ms (voir plus bas encore)... et effectivement j'avais déjà observé ce comportement où il teste la même valeur sur différents essais, du coup c'est bien lié avec time().

              Ça devient clair, je comprends la source de ce résultat, merci :). Ça aurait dû être évident en plus, étant donné que j'utilise difftime à la fin pour obtenir mon temps en secondes mais sur le moment j'ai dû me dire que cette méthode faisait un calcul plus poussé en interne...

              -
              Edité par xoxotf il y a moins de 30s

              Oui, en programmation ce n'est jamais évident de savoir ce qui est sensé marcher, et ou ça plante exactement. En général ça plante à l'endroit que l'on suspecte le moins ! Quand on est perdu et qu'on ne sait pas trop d'où regarder, il ne faut pas hésiter à insérer des print un peu partout, afin de trouver l'endroit où c'est louche. Si tu avais printé les valeurs choisies à chaque itération tu t'en serais rendu compte tout de suite, et de fil en aiguille tu aurais trouvé le problème - mais voilà il faut penser à le faire :)

              Dans la plupart des cas utiliser un débogueur peut t'aider à voir le problème plus facilement, mais dans ton cas précis, le débogueur aurait augmenté le temps d'exécution donc même avec un débogueur tu n'aurais pas vu le bug en fait. Ceci dit, dans le cas général, je t'encourage à apprendre à utiliser un débogueur, ça demande un peu de temps d'apprendre comment ça fonctionne en amont, mais une fois que tu sais t'en servir, tu gagnes un temps énorme.

              Le débogage c'est surtout une histoire d'expérience - à force de croiser des comportements bizarres, tu finiras par avoir l'intuition de "où regarder".

              Si le sujet est résolu n'oublie pas de le marquer en tant que tel :) Et bonne continuation pour la suite !

              PS : la probabilité d'avoir deux doublons à la suite n'est pas négligeable en fait : si tu tires 10 éléments, cette proba est de (1 - (99/100)^9) = 8% ;) C'est moins élevé que la proba d'avoir deux mêmes éléments dans un tableau, mais ça arrive.

              • Partager sur Facebook
              • Partager sur Twitter
                28 avril 2019 à 17:00:20

                Merci du temps consacré. Sujet résolu :D
                • Partager sur Facebook
                • Partager sur Twitter

                Comportement de sleep

                × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                • Editeur
                • Markdown