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

Python Discussion :

Exécuter des parties de codes en parallèle


Sujet :

Python

  1. #1
    Nouveau membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2019
    Messages
    6
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Seine et Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Avril 2019
    Messages : 6
    Par défaut Exécuter des parties de codes en parallèle
    Bonjour,
    J'ai pas mal cherché sur le net mais je ne trouve rien (ou ne comprend pas) comment l'appliquer à mon cas.
    Je ne sais pas trop comment l'expliquer alors je vais plutôt essayer de vous illustrer ma question.
    Prenons ce code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    Points = [[0, i] for i in range(4)]
    while True:
        for i in range(4):
            Points[i][0] += Points[i][1]
        print ([Points[i][0] for i in range(4)])
    J'aimerais le modifier de façon à ce que chaque itération de la boucle for s'exécute en parallèle plutôt que les unes après les autres.
    Sur un programme plus complexe, ca devrait améliorer la rapidité d'exécution non ?
    Merci et bonne journée.

  2. #2
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 741
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 741
    Par défaut
    Salut,

    Citation Envoyé par Brisingle Voir le message
    Sur un programme plus complexe, ca devrait améliorer la rapidité d'exécution
    Ce n'est pas si simple.
    Exécuter en parallèle, c'est démarrer le programme, créer un certain nombre de workers, leur distribuer le boulot et collecter/assembler les résultats.

    Vous voyez (ou pas) qu'il y a des portions "séquentielles", et des portions "parallélisées" (lorsque les workers bossent).

    La portion séquentielle "borne" le temps qu'on va gagner à paralléliser.

    Pour les détails, voir l'article Wikipedia sur la loi de Amdhal.

    Après pour faire une opération comme Points[i][0] += Points[i][1], c'est l'ajout de deux vecteurs... et plutôt que paralléliser, il sera plus intéressant de "vectoriser" (en utilisant la carte graphique par exemple).

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  3. #3
    Nouveau membre du Club
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2019
    Messages
    6
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Seine et Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Avril 2019
    Messages : 6
    Par défaut
    Citation Envoyé par wiztricks Voir le message
    Ce n'est pas si simple.
    Exécuter en parallèle, c'est démarrer le programme, créer un certain nombre de workers, leur distribuer le boulot et collecter/assembler les résultats.

    Vous voyez (ou pas) qu'il y a des portions "séquentielles", et des portions "parallélisées" (lorsque les workers bossent).

    La portion séquentielle "borne" le temps qu'on va gagner à paralléliser.
    J'avoue ne pas avoir tout compris... ^^'

    Citation Envoyé par wiztricks Voir le message
    Après pour faire une opération comme Points[i][0] += Points[i][1], c'est l'ajout de deux vecteurs... et plutôt que paralléliser, il sera plus intéressant de "vectoriser" (en utilisant la carte graphique par exemple).
    Qu'entendez vous par "vectoriser" ? Parce que la c'est un exemple vraiment bidon, dans le code que j'utilise, il y a bien d'autres opérations dans la boucle for.

    Merci de votre réponse

  4. #4
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 741
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 741
    Par défaut
    Citation Envoyé par Brisingle Voir le message
    J'avoue ne pas avoir tout compris... ^^'
    Je vous ai mentionné un article de Wikipedia pour vous permettre d'approfondir.

    Citation Envoyé par Brisingle Voir le message
    Qu'entendez vous par "vectoriser" ? Parce que la c'est un exemple vraiment bidon, dans le code que j'utilise, il y a bien d'autres opérations dans la boucle for.
    Si vous avez 2 vecteurs à N éléments comme par exemple (1, 1, 1, 1, 1) et (2, 2, 2, 2, 2) on peut les ajouter élément par élément (dans une boucle par exemple) ou avoir une "machine" vectorielle qui effectue ces additions en une seule opération/instruction.

    Si vous ne connaissez pas le concept vous pouvez regarder ce que raconte Wikepedia sur le sujet.

    Citation Envoyé par Brisingle Voir le message
    dans le code que j'utilise, il y a bien d'autres opérations dans la boucle for.
    Avant de vectoriser ou de paralléliser, on essaie d'optimiser son code... Si on est au bout du bout, on fait une estimation de combien de temps on espère gagner en parallélisant ou en vectorisant pour savoir si çà vaut le coût (car il va falloir réorganiser tout ou partie du code pour que çà puisse fonctionner).

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  5. #5
    Expert confirmé
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 486
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 486
    Billets dans le blog
    6
    Par défaut
    Bonjour,

    Faire que plusieurs opérations puissent se dérouler "en même temps" peut se faire en Python de plusieurs façons:

    - par thread. Mais on ne gagne pas de temps puisque les threads vont se partager le même cœur du CPU. Celui-ci va travailler alternativement pour chacun des threads, mais ce sera tellement rapide qu'à notre échelle, on aura l'impression que ce sera "en même temps". Exemple d'utilisation: faire un calcul très long dans un programme graphique gèlerait le graphique à l'écran si on ne le faisait pas dans un thread.

    - par processus. Là, c'est plus intéressant puisque à la création du processus, l'OS l'affectera à l'un des cœurs disponibles (s'il y en a un!) du CPU. On utilise le module Python "multiprocessing". On peut avec lui créer plusieurs processus, chacun pouvant faire un traitement identique ou non sur les données. On peut même imaginer que certains processus en attendent d'autres selon les données, et même qu'ils s’exécutent en permanence et vont chercher eux-mêmes du travail s'il y en a en attente. Bref, on fait ce qu'on veut, et ça marche très bien, mais je n'ai pas dit que c'était facile à programmer...

    - cas particulier du traitement par processus: le module "concurrent.futures". Là, il s'agit de réaliser la même opération sur une liste d'arguments en utilisant les cœurs du CPU au maximum. Et c'est facile à programmer! Et bien sûr, pour faire ça, chaque traitement doit être indépendant des autres! Pour prendre un exemple concret, dans le cadre d'un programme de recherche de photos, il a fallu que je calcule des centaines de vignettes en attente d'affichage. Comme ces calculs de vignettes sont indépendants des autres, le calcul en parallèle fait gagner du temps.

    Enfin, soyons clairs sur un point: on ne peut gagner du temps que si le travail à faire est suffisamment important. S'il ne l'est pas assez, le temps pour mettre en place les processus et assurer les échanges de données seront trop importants par rapport au temps de traitement. Cela fera que, par exemple avec un CPU à 4 cœurs, le temps ne sera divisée que par 1.5 ou 2 au lieu de 4.

    Voilà un petit exemple pour illustrer mon propos: un test pour savoir si un nombre est premier ou non:

    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
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    # -*- coding: utf-8 -*-
     
    from math import sqrt, floor
    import concurrent.futures
    from random import randint
    from time import perf_counter
     
    ##############################################################################
    def estpremier(n):
        """dit si un nombre est premier (renvoie True ou False) par la méthode des 
           divisions
        """
        if n<2:
            return False
        if n % 2==0:
            return n == 2 # pour les nombres pairs, seul 2 est premier
        d, rac = 3, int(floor(sqrt(n)))
        while d <= rac:
            if n % d == 0:
                return False # diviseur trouvé => n n'est pas premier
            d += 2 # nombre impair suivant
        return True # aucun diviseur trouvé: n est premier
     
    ##############################################################################
    if __name__ == '__main__':
     
        #=========================================================================
        # génère des nombres aléatoires
        nombres = [randint(100, 10**15-1) for i in range(0, 1000)]
        print(nombres)
        print()
     
        #=========================================================================
        # calcul utilisant les coeurs du CPU multicores
        tps1 = perf_counter()
        resultat1 = []
        with concurrent.futures.ProcessPoolExecutor() as executor:
            for nombre, resultat in zip(nombres, executor.map(estpremier, nombres)):
                resultat1.append([nombre, resultat])
        tps1 = perf_counter()-tps1
        print(resultat1)
        print(tps1)
        print()
     
        #=========================================================================
        # calcul normal dans une boucle
        tps2 = perf_counter()
        resultat2 = []
        for nombre in nombres:
            resultat2.append([nombre, estpremier(nombre)])
        tps2 = perf_counter()-tps2
        print(resultat2)
        print(tps2)
    Avec mon CPU à 4 cœurs, et sur une exécution quelconque, j'ai obtenu sur les mêmes données 35 secondes pour la méthode normale (boucle séquentielle), et 10 secondes pour la méthode avec concurrent-futures, soit un temps divisé par 3.5...

    Bien sûr, mon propos très simplifié ne remplace pas la nombreuse littérature sur le sujet, y compris les liens déjà donnés!

  6. #6
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 835
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 835
    Billets dans le blog
    1
    Par défaut
    Bonjour
    Citation Envoyé par tyrtamos Voir le message
    Voilà un petit exemple pour illustrer mon propos: un test pour savoir si un nombre est premier ou non:
    Excellent cet exemple. Je ne connaissais pas "concurrent.futures" (et chaque fois que je vois tes posts ou ceux de wiztricks je réalise que je connais que dalle en réalité) mais j'ai adoré

    Je me suis ensuite amusé à y calquer un test utilisant multiprocessing. Mais j'ai aussi enlevé le "append" pouvant fausser les tests
    Code python : 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
    from multiprocessing import Pool
    ... (le début pris dans le code de tyrtamos...)
     
    if __name__ == '__main__':
    	# génère des nombres aléatoires
    	nombres=tuple(randint(100, 10**15-1) for i in range(0, 1000))
    	print(nombres)
    	print()
     
    	# calcul normal dans une boucle
    	tps = perf_counter()
    	resultat=tuple((n, isPremier(n)) for n in nombres)
    	tps = perf_counter()-tps
    	#print(tuple((n, r) for (n, r) in resultat if r))
    	print("base: ", tps)
    	print()
     
    	# calcul utilisant concurrent.futures
    	tps = perf_counter()
    	resultat = []
    	with concurrent.futures.ProcessPoolExecutor() as executor:
    		resultat=tuple((n, r) for (n, r) in zip(nombres, executor.map(isPremier, nombres)))
    	tps = perf_counter()-tps
    	#print(tuple((n, r) for (n, r) in resultat if r))
    	print("concurrent:", tps)
    	print()
     
    	# calcul utilisant multiprocessing
    	tps = perf_counter()
    	resultat = []
    	with Pool(4) as p:
    		resultat=tuple((n, r) for (n, r) in zip(nombres, p.map(isPremier, nombres)))
    	tps = perf_counter()-tps
    	#print(tuple((n, r) for (n, r) in resultat if r))
    	print("pool:", tps)

    Et au résultat
    base: 30.387541256000986
    concurrent: 8.219779146995279
    pool: 7.944510806992184

    Mais cela ne veut pas dire grand chose car en le lançant une seconde fois...
    base: 26.867525838999427
    concurrent: 7.170248055990669
    pool: 8.165446345999953



    PS: accessoirement j'ai eu un mal fou à faire marcher ce code car à chaque fois, il me sortait en erreur avec en dernière ligne AttributeError: module 'signal' has no attribute 'SIGTERM'. Et quand je prenais le code source d'exemple de la doc de multiprocessing, ça fonctionnait. Sauf que l'exemple de la doc je l'exécutais dans "/tmp" tandis que ce code je l'exécutais là où je mets mon "fourre-tout" des exemples Python.
    J'ai finalement fini par trouver. C'était à cause d'un autre source Python nommé "signal.py" qui était placé dans le même dossier
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  7. #7
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 741
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 741
    Par défaut
    Salut,

    Citation Envoyé par Sve@r Voir le message
    Excellent cet exemple.
    C'est l'exemple donné dans la documentation du module concurrent.futures.

    Je ne l'aime pas parce qu'il montre juste qu'il est facile grâce au fonctionnalités du module de paralléliser l'appel à une fonction "pure" (ce qui va de soi).

    Hélas, paralléliser un code qui n'a pas été pensé pour est une autre paire de manche...

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

Discussions similaires

  1. Exécuter une partie de code sous une autre identité
    Par Magicmodjo dans le forum SharePoint
    Réponses: 3
    Dernier message: 04/12/2007, 16h32
  2. Réponses: 5
    Dernier message: 28/08/2007, 14h00
  3. Temps d'exécution des portions de codes
    Par xela dans le forum Autres éditeurs
    Réponses: 2
    Dernier message: 23/01/2007, 22h29
  4. Réponses: 4
    Dernier message: 04/08/2006, 01h02
  5. Réponses: 4
    Dernier message: 01/02/2006, 14h56

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