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 :

Processus et Affinités


Sujet :

C#

  1. #1
    Membre éclairé
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    310
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 310
    Par défaut Processus et Affinités
    Bonjour,

    Je développe un programme très gourmand en ressource CPU, non multi-threadé (un seul thread principal pour l'instant).

    Quand je lance mon exe, est-ce que :
    - Windows va-t-il naturellement utiliser tous la totalité des coeurs de mon processeur (8 cores chez moi) ?
    - Pour être sûr qu'il le fasse, j'utiliserais :
    Process.GetCurrentProcess().ProcessorAffinity = (System.IntPtr) ?;
    Ainsi mon problème est de remplacer le "?" par le bon mask, je ne comprends pas comment cela fonctionne, j'aimerai lui spécifier "les 8 coeurs"

    Merci pour votre aide.

  2. #2
    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 : 44
    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
    Par défaut
    Citation Envoyé par jeremm Voir le message
    - Windows va-t-il naturellement utiliser tous la totalité des coeurs de mon processeur (8 cores chez moi) ?
    Pour un seul thread, il ne peut utiliser qu'un seul coeur...

  3. #3
    Membre éclairé
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    310
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 310
    Par défaut
    Pardon j'ai écris une boulette j'ai un thread main et un tread de calcul. Donc 2.
    Actuellement par exemple il consomme les 8 coeurs pour les calculs. Hier il ne prenait que 2 coeurs.
    Comme gère-t-il cela ? C'est assez flou.
    C'est pourquoi j'aimerai le forcer à travers le ProcessorAffinity à 8 coeurs. Comme remplir le mask ?

    Merci

  4. #4
    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 : 44
    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
    Par défaut
    Citation Envoyé par jeremm Voir le message
    Actuellement par exemple il consomme les 8 coeurs pour les calculs. Hier il ne prenait que 2 coeurs.
    Euh, ça me parait très surprenant... un thread ne peut utiliser qu'un coeur, donc 2 threads ne peuvent utiliser que 2 coeurs à la fois au maximum. Par contre l'OS peut toujours décider de passer un thread d'un coeur à un autre...

  5. #5
    Membre éclairé
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    310
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 310
    Par défaut
    Ce n'est justement pas le travail du Scheduler de répartir les calculs lourds sur plusieurs coeurs ? En tout cas quand je lance mon exe je vois bien les 8 coeurs s'emballer à envrion 80% d'utilisation chacun et constant.
    Et si on peut assigner une valeur à ProcessorAffinity (que ce soit en C# ou a travers le gestionnaire de processus) c'est qu'il est bien possible d'utiliser un ou plusieurs coeurs selon notre envie non ?

  6. #6
    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 : 44
    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
    Par défaut
    Citation Envoyé par jeremm Voir le message
    Ce n'est justement pas le travail du Scheduler de répartir les calculs lourds sur plusieurs coeurs ?
    Le scheduler répartit les tâches (= threads) sur les coeurs et donne la main successivement à tel ou tel thread, mais il ne peut pas "subdiviser" les tâches. Tous les calculs ne sont pas parallélisables automatiquement, c'est quelque chose qu'il faut gérer soi-même (soit manuellement en créant plusieurs threads, soit avec des librairies spécialisées comme la Task Pallel Library)

    Citation Envoyé par jeremm Voir le message
    En tout cas quand je lance mon exe je vois bien les 8 coeurs s'emballer à envrion 80% d'utilisation chacun et constant.
    En quoi consiste ton traitement ? Peut-être que tu utilises des composants qui sont implicitement multithread...

    Citation Envoyé par jeremm Voir le message
    Et si on peut assigner une valeur à ProcessorAffinity (que ce soit en C# ou a travers le gestionnaire de processus) c'est qu'il est bien possible d'utiliser un ou plusieurs coeurs selon notre envie non ?
    Non, c'est pour indiquer sur quel(s) processeur(s) le process peut s'exécuter

    Citation Envoyé par MSDN
    Gets or sets the processors on which the threads in this process can be scheduled to run.

  7. #7
    Membre Expert Avatar de DonQuiche
    Inscrit en
    Septembre 2010
    Messages
    2 741
    Détails du profil
    Informations forums :
    Inscription : Septembre 2010
    Messages : 2 741
    Par défaut
    Il est en fait déconseillé de spécifier une affinité de thread. La raison tient à la fois au fait que d'autres programmes et services peuvent tourner en tâche de fond, ce que le développeur d'une application ne peut pas prévoir, et qu'il est typiquement difficile pour le programmeur de connaître à l'avance la charge de chaque thread (alors que le scheduler s'appuie, lui, sur les mesures relevées). C'est une technique avancée et puisque apparemment tu ne sais pas très bien ce que tu fais, laisse plutôt le scheduler se débrouiller. De toute façon, l'affinité par défaut spécifie que chaque thread peut potentiellement est exécuté sur n'importe quel coeur.

    Concernant les "huit coeurs", en es-tu certain ? Il est beaucoup plus probable qu'il s'agisse d'un processeur quatre coeurs avec hyperthreading. L'hyperthreading est un procédé dans lequel chaque coeur est capable de fonctionner comme deux coeurs plus lents. Selon la charge du système, un coeur pourra fonctionner à plein régime ou être traité comme deux coeurs plus lents. Toutefois, en pratique, le résultat est assez mitigé et l'hyperthreading peut apporter un gain allant d'appréciable à nul. En fait on a même vu des applications être légèrement pénalisées par l'hyperthreading.

    A part ça, Tomlev a clarifié les choses : c'est au développeur de découper son programme en threads et au scheduler de répartir les threads de toutes les applications sur les différents coeurs et processeurs. S'il n'y a vraiment que deux threads, Windows ne peut pas utiliser plus de deux coeurs (sauf si d'autres applis tournent en fond).

    Enfin, sur la question de pourquoi Windows ne peut pas automatiquement diviser un thread en plusieurs tâches parallèles, cela tient au fait que la parallélisation automatique est un problème très complexe, nécessitant une compréhension intime de l'usage et du partage des données au travers du programme (puis-je paralléliser telle boucle ?) et du fonctionnement de ce dernier (est-il intéressant de paralléliser telle boucle ?). Les algos permettant de faire cela sont très gourmands en ressources (longue analyse préalable du code) et encore loin d'égaler les résultats que peut produire un être humain (les meilleurs systèmes exigent du programmeur qu'il donne des indices). Les systèmes d'exploitation considèrent donc que l'humain a bien fait son travail et que la parallélisation est déjà optimale. Un OS qui tenterait de paralléliser automatiquement risquerait fort de réduire l'efficacité des programmes déjà optimisés.

  8. #8
    Membre éclairé
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    310
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 310
    Par défaut
    Bonjour,

    Merci pour ces explications très intéressantes.
    Mon CPU : Xeon E5440, d'après la spec il y a effectivement 4 cores. Question : Dans le gestionnaire de processus onglet performances je vois 8 graph. C'est donc de l'hyperthreading chaque core possède 2 cores plus lents ?

    Pour mes calculs j'utilise effectivement des librairies externe dont je ne possède pas les sources, mais le développeur m'assure qu'elles ne sont pas multi-threadées.

    Je me demande par quel miracle mon application peut tourner sur les "8 graphs" du gestionnaire de processus (donc sur 4 coeurs physiques avec utilisation de l'hyperthreading apparemment) alors que techniquement je n'ai pas développé en multithread ?

  9. #9
    Membre Expert Avatar de DonQuiche
    Inscrit en
    Septembre 2010
    Messages
    2 741
    Détails du profil
    Informations forums :
    Inscription : Septembre 2010
    Messages : 2 741
    Par défaut
    Concernant le processeur, il utilise effectivement l'hyperthreading. Note que la formulation "possède deux cores en plus" est incorrecte. Vois-le plutôt comme la possibilité dans certains cas pour un core de traiter les instructions deux par deux ou de se comporter comme deux cores différents les traitant une par une.

    Maintenant, concernant l'utilisation des 8 pseudo-cores, je ne peux pas te répondre sans regarder ton code source. Mais à l'évidence celui-ci ne fonctionne pas comme tu le penses.

  10. #10
    Membre éclairé
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    310
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 310
    Par défaut
    Ok.
    Donc tu penses que les calculs de ma librairie externe sont finalement multi-threadés, sinon il n'y aurai pas de raison que le programme utilise les 8 pseudo-cores.
    Le problème c'est que parfois il n'utilise que 1 core, du coup mes calculs sont très lent.
    Je n'ai malheureusement pas la possibilité de forcer l'OS à utiliser tous ses cores ?

  11. #11
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Février 2003
    Messages
    2 201
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Belgique

    Informations forums :
    Inscription : Février 2003
    Messages : 2 201
    Par défaut
    Il faut revoir l'architecture de ton application pour qu'elle puisse faire du multicore.
    Réussir a découper ton programme en plusieurs tache qui pourront tournée en parallèle et ensuite être resynchroniser

    Si tu as qu'un seul thread dans ton application et que celle-ci utilise plusieurs core c'est que des partie de ton programme font du multrithreading
    Soit la librairie, soit tu fais appel sans le savoir à d'autre Thread.
    Si c'est ta librairie externe, elle peut lancer des threads en fonctions des opérations que tu lui demandes et donc déprendre à chaque fois du cas que tu utilises

  12. #12
    Membre éclairé
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    310
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 310
    Par défaut
    Merci.
    J'avance peu à peu grâce à vous.
    Je pars donc du principe que ma librairie est multi-threadé.
    Le mystère reste entier : après une compilation en release le premier lancement de mon programme calcule bien sur les 8 cores, alors que le second ou le 3ième lancement des calculs ne prendra qu'un seul coeur. Avec-vous une idée ? Est-ce Windows ou ma librairie la source du problème ?

  13. #13
    Membre Expert Avatar de DonQuiche
    Inscrit en
    Septembre 2010
    Messages
    2 741
    Détails du profil
    Informations forums :
    Inscription : Septembre 2010
    Messages : 2 741
    Par défaut
    Vu comme tu décris la chose, je pencherais davantage pour des threads externes. La durée d'exécution de ton programme est assez courte je présume ? Cela pourrait être l'antivirus examinant ce nouveau fichier, le framework compilant ton programme en natif, le service d'indexation Windows examinant tes ressources, Visual Studio imprimant la sortie de ton programme, etc.

    Cela dit, il est difficile de se prononcer quand on ne connaît pas le code en question. Je peux précisément t'expliquer ce qui se passe dans mes programmes mais, sans boule de cristal, c'est plus difficile pour le tien...

  14. #14
    Membre éclairé
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    310
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 310
    Par défaut
    OK. Je ne vais pas coller mon code ici il fait des centaines de classes..
    Citation Envoyé par DonQuiche Voir le message
    La durée d'exécution de ton programme est assez courte je présume ?
    Non, les calculs durent environ 30 minutes avec 8 cœurs et plusieurs heures avec un seul.
    Il calcule, enregistre des données dans un fichier, en boucle.

    Je me doute que l'antivirus analyse ce fichier mais il le fait à chaque fois que je lance mes calculs, donc la reproductibilité du temps de calcul devrait être plutot bonne :/

  15. #15
    Membre Expert Avatar de DonQuiche
    Inscrit en
    Septembre 2010
    Messages
    2 741
    Détails du profil
    Informations forums :
    Inscription : Septembre 2010
    Messages : 2 741
    Par défaut
    Bigre ! Non, alors, ça ne peut venir que de ton code. Reprenons par le début, que fait-il au juste ? Utilise t-il des opérations asynchrones (cherche dans ton code tous les "Begin" et "Async") ? Quels sont les types de System.Threading que tu utilises (là aussi, une petite recherche textuelle) ? Outre le framework, quels sont les composants externes (DB, biblios, etc) ? Les threads portent-ils un nom (tu peux le voir dans la fenêtre de déboguage, fais le test dans le cas à 8 coeurs et dans le cas à 1 coeur) ?

  16. #16
    Membre éclairé
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    310
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 310
    Par défaut
    Citation Envoyé par DonQuiche Voir le message
    Reprenons par le début, que fait-il au juste ?
    Des calculs trigonométriques complexes liés à des calculs d'orbites. Je stoke les résultats en binaire dans un fichier.

    Alors, aucun "Begin" ni aucun System.Threading dans mon code. J'utilise un BackgroundWorker pour lancer mes calculs.

    Outre le framework, quels sont les composants externes (DB, biblios, etc) ?
    Rien à part la librairie qui me permet "d'objectiser" et de me simplifier les calculs. Pas de db, juste un fichier de sortie.

    Les threads portent-ils un nom (tu peux le voir dans la fenêtre de déboguage, fais le test dans le cas à 8 coeurs et dans le cas à 1 coeur) ?
    Non.

    L'exemple le plus classique :
    - Je lance mon exe, appuie sur "start les calculs" : les 8 coeurs s'emballent, CPU à ~70%.
    - le calcul s'arretent au bout de 30min. Je refait un "start" : 1 core seulement. CPU à ~12%. Rageant !
    - Je ferme mon programme, le relance, rappuie sur start : 8 coeurs OK.

  17. #17
    Membre Expert Avatar de DonQuiche
    Inscrit en
    Septembre 2010
    Messages
    2 741
    Détails du profil
    Informations forums :
    Inscription : Septembre 2010
    Messages : 2 741
    Par défaut
    Dans ce cas, pourrais-tu nous montrer la partie du code où tu utilises le BackgroundWorker ? Et si possible nous donner le nom de cette biblio ? Tu peux aussi suspendre le programme en cours d'exécution et voir le point d'arrêt de chaque thread, cela te permettra de savoir ce qu'ils font et où ils ont démarré (bas de la pile des appels).

    Maintenant, concernant cette différence de comportement, ça va (comme toujours) être un détail à la noix tel qu'une race condition.

  18. #18
    Membre éclairé
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    310
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 310
    Par défaut
    C'est un backgroundWorker très classique :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    worker.WorkerReportsProgress = true;
    worker.WorkerSupportsCancellation = true;
    worker.DoWork += worker_DoWork;
    worker.RunWorkerCompleted += worker_RunWorkerCompleted;
    worker.ProgressChanged += worker_ProgressChanged;
    Le dowork execute les calculs (qui s'étendent sur plusieurs classes, non montrés ici donc)

    Le nom de la biblio ne servirait à rien car elle a été développé en interne (elle n'est pas publique sur internet).
    Tu peux aussi suspendre le programme en cours d'exécution et voir le point d'arrêt de chaque thread, cela te permettra de savoir ce qu'ils font et où ils ont démarré (bas de la pile des appels
    Comment regarder la pile des appels sous VS2010 ?

    Merci.

  19. #19
    Max
    Max est déconnecté
    Expert confirmé

    Avatar de Max
    Homme Profil pro
    Artisan développeur
    Inscrit en
    Mai 2007
    Messages
    2 954
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Artisan développeur
    Secteur : Industrie

    Informations forums :
    Inscription : Mai 2007
    Messages : 2 954
    Par défaut
    Citation Envoyé par jeremm Voir le message
    Comment regarder la pile des appels sous VS2010 ?

    Merci.
    Lorsque tu es sur ton point d'arrêt, menu Debug > Windows > Call Stack (ou Ctrl+D, C). Après tu peux t'amuser avec

  20. #20
    Membre éclairé
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    310
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 310
    Par défaut
    Ok.

    Je viens de remarquer que la différence de comportement ne se produit qu'en Release. En mode debug, je n'ai pas de ralentissements lors du second calcul.

    Un idée ?

Discussions similaires

  1. Processus paralleles
    Par Lyes dans le forum Threads & Processus
    Réponses: 4
    Dernier message: 11/02/2003, 13h04
  2. 1 variable pour 2 processus
    Par kacedda dans le forum POSIX
    Réponses: 2
    Dernier message: 11/02/2003, 06h32
  3. probleme avec les processus
    Par saidi dans le forum Autres éditeurs
    Réponses: 1
    Dernier message: 05/02/2003, 00h18
  4. [VB6] [Système] Tuer un processus courant
    Par mdoyer dans le forum VB 6 et antérieur
    Réponses: 7
    Dernier message: 22/10/2002, 14h47
  5. Réponses: 2
    Dernier message: 04/10/2002, 09h13

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