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 :

Optimisation de code trop lent


Sujet :

Python

  1. #1
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2015
    Messages
    42
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Communication - Médias

    Informations forums :
    Inscription : Mars 2015
    Messages : 42
    Par défaut Optimisation de code trop lent
    Bonjour à tous,

    J'ai besoin d'un coup de main pour optimiser mon code car il est trop long à l'exécution.

    En fait, j'ai une longue liste d'url dans laquelle je récupère des informations pour chaque URL.

    Etant donnée la longueur de la liste, lorsque j'exécute mon code, cela prend énormément de temps.

    Ainsi, je voudrais optimiser mon code, afin que l'exécution se fasse plus rapidement.
    J'ai pu voir notamment qu'il existait une possibilité de faire un multiprocessing pour exécuter plusieurs URL à la fois dans mon code. Mais je n'ai pas réussi à utiliser cette méthode qui est nouvelle pour moi.

    Voici mon code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    resultat =[] # Création de la variable qui va contenir les informations.
     
     
    # On boucle sur chaque URL pour obtenir les informations à travers la fonction data() qui prend en paramètre une URL.
     
    for item in range(0,len(list_url)):
     
        resultat.append(data(list_url[item])) # Ajout des informations obtenues dans la variable resultat.
        if item % 10 == 0:
            print("Url en cours : "+list_url[item]+" "+str(item)) # J'affiche l'URL en cours, pour toutes les 10 URL.
    Si je compte une 30 de seconde par URL, que je multiplie par le nombre d'URL. Le temps d'execution peut vite passer en jours et non en heure.

    C'est la raison pour laquelle, je souhaiterai pouvoir utiliser une méthode qui puisse exécuter plusieurs URL à la fois.

    Je vous remercie d'avance pour l'aide que vous m'apporterez.

  2. #2
    Membre expérimenté Avatar de zancrows
    Homme Profil pro
    Étudiant
    Inscrit en
    Décembre 2016
    Messages
    159
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Côtes d'Armor (Bretagne)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2016
    Messages : 159
    Par défaut
    Bonjour,

    Ton code actuellement est synchrone, il fait un requête, attend le retour, puis fait le traitement et ainsi de suite.
    Tant que ton traitement n'est pas fait tu peux pas faire de prochaine requête.
    Ce que tu peux faire, s'est regarder du côté de l'asynchronisme (AIOHTTP, threading, asyncio, etc...), pour rendre "non bloquant" ton code.
    Le multiproccessing peut être aussi une solution comme tu l'a évoqué.

  3. #3
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 754
    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 754
    Par défaut
    Salut,

    Citation Envoyé par frutz Voir le message
    J'ai besoin d'un coup de main pour optimiser mon code car il est trop long à l'exécution.
    Si vous ne l'exécutez qu'une seule fois, çà n'a pas trop d'importance excepté qu'en cas de plantage du réseau ou de l'ordinateur on voudrait bien ne pas avoir à tout refaire.
    Ce qui suppose savoir où on est en pour redémarrer à partir de là.

    Si on doit exécuter ce code plusieurs fois, pas tous les contenus ont été mis à jour depuis le dernier passage et inutile de récupérer des données qu'on a déjà.
    Cela se fait au niveau de la requête HTTP.

    Arrivé là, on sait reprendre le boulot là où on s'est arrêté et ne recopier que ce qui a été mis à jour.

    Reste à ajouter des bras pour que leur distribuer une partie du boulot histoire que çà se termine plus tôt.
    N process, ou threads système ou threads utilisateur (asyncio) peuvent être envisagés...
    Citation Envoyé par frutz Voir le message
    J'ai pu voir notamment qu'il existait une possibilité de faire un multiprocessing pour exécuter plusieurs URL à la fois dans mon code.
    Mais je n'ai pas réussi à utiliser cette méthode qui est nouvelle pour moi.
    Vu le type d'activité, l'emballage concurrent.futures des threads ou du multiprocessing devrait être plus facile.

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

  4. #4
    Membre Expert

    Homme Profil pro
    Ingénieur calcul scientifique
    Inscrit en
    Mars 2013
    Messages
    1 229
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur calcul scientifique

    Informations forums :
    Inscription : Mars 2013
    Messages : 1 229
    Par défaut
    Il faudrait présenter la fonction data, et mesurer les temps d’exécution en séparant, dans cette fonction, le téléchargement du contenu de l'URL, et le traitement fait sur ce contenu pour en extraire les données voulues.

    Si sur les 30 secondes, 25 sont passées à téléchargé les données, alors il n'y a pas grand chose à faire. Avec le multithreading vous pourrez recouvrir votre temps de téléchargement par du temps de calcul, (donc gain de 5 secondes par URL). C'est toujours ca de pris, mais le gain ne va pas être fulgurant par rapport à l'artillerie que vous allez devoir déployer pour mettre ca en place

    Si au contraire, sur les 30 secondes, seulement quelques unes sont pour le téléchargement, et le reste pour le traitement de la donnée brute pour extraire la donnée qu'il vous faut, alors là en effet c'est votre CPU qui vous limite (et ca peut aussi se vérifier en allant dans votre gestionnaire des taches windows, et de regarder dans l'onglet des ressources machines à combien tourne votre CPU. Lorsque vous lancez votre code le travail des CPUs s'accroissent. Si vous avez 4 coeurs alors vous devriiez voir la charge de vos CPU augmenter d'environ 25%, ce qui veut dire dans ce cas que l'un de vos 4 CPUS, qui ne faisait rien, devient à présent occupé à 100%). Dans ce cas là :
    1) avant de se diriger vers du multithreading, il faut regarder de plus près l'algorithme d'extraction de l'information. En faisant un peu différement, vous pourriez optimiser son temps d’exécution. C'est par là qu'il faut commencer. On imagine pas parfois, mais on fait des choses qui numériquement ont de lourds impacts, alors qu'en faisant autrement on est du style 100 ou 1000 fois plus rapide.
    2) Une fois l'extraction de données optimisée, le multithreading vous permetterait d'utiliser tous les CPUs de votre machine, et pas juste un seul, et donc de diviser le temps de calcul potentiellement par 4 ou 8 selon votre nombre de CPUs.

  5. #5
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 754
    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 754
    Par défaut
    Citation Envoyé par lg_53 Voir le message
    Si sur les 30 secondes, 25 sont passées à téléchargé les données, alors il n'y a pas grand chose à faire. Avec le multithreading vous pourrez recouvrir votre temps de téléchargement par du temps de calcul, (donc gain de 5 secondes par URL).
    Sachant que le multithreading Python limite la capacité de calcul à 1 CPU, 6 threads chargeront 6 pages en 30 s. plutôt qu'attendre 6x30s = 3 mns.

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

  6. #6
    Membre Expert

    Homme Profil pro
    Ingénieur calcul scientifique
    Inscrit en
    Mars 2013
    Messages
    1 229
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur calcul scientifique

    Informations forums :
    Inscription : Mars 2013
    Messages : 1 229
    Par défaut
    Citation Envoyé par wiztricks Voir le message
    Sachant que le multithreading Python limite la capacité de calcul à 1 CPU, 6 threads chargeront 6 pages en 30 s. plutôt qu'attendre 6x30s = 3 mns.

    - W
    Oui j'ai supposé ici que c'était la bande passante qui limite. Donc on peut téléchargé plusieurs trucs en même temps, mais si c'est la bande passante qui nous limite, en faire plusieurs en même temps ne va pas faire gagner beaucoup de temps, voire, pourrait même en faire perdre.

  7. #7
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 840
    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 840
    Billets dans le blog
    1
    Par défaut
    Bonjour

    En plus de tout ce qui a été dit sur le temps de téléchargement par rapport au temps de calcul, moi je m'interroge sur la quantité d'infos à stocker. En effet le PO prévois plusieurs jours pour tout télécharger à raison de 30 secondes par URL ce qui donne, si on part sur 86400 secondes par journée avec plusieurs jours (allez disons 2 jours) 5760 URL à télécharger (et quand on parle d'URL il faut traduire par "tout le texte qu'il y a derrière et n'y aurait-il pas aussi des photos???"). Ok Python est capable d'engloutir cette masse mais quoi qu'on fasse, que ce soit en mono ou en multiprocessing, ça lui prendra malgré tout un temps incompressible. D'autant plus avec ce list.append() qui est tout sauf optimal (la liste en intension aurait au-moins évité cette instruction).

    lg_53 a parlé d'algorithme d'extraction, moi je parlerais déjà de l'utilité de cette procédure (faut-il vraiment tout stocker en RAM?) et admettons que ce soit vraiment nécessaire (?), alors surtout du modèle utilisé pour stocker toutes ces infos. A ce niveau, une liste ce n'est plus du tout adéquat.
    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]

  8. #8
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 754
    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 754
    Par défaut
    Citation Envoyé par lg_53 Voir le message
    Oui j'ai supposé ici que c'était la bande passante qui limite.
    C'est vrai qu'en disant 30s. par URL, on ne sait pas trop quelle ressource fait goulot d'étranglement.

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

  9. #9
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Mars 2015
    Messages
    42
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : Communication - Médias

    Informations forums :
    Inscription : Mars 2015
    Messages : 42
    Par défaut
    Merci à tous pour vos réponses.

    Je ne sais pas pas où commencer, je vais essayer de vous apporter d'autres éléments de réponse.

    Dans mon script j'utiliser une fonction data qui prend en paramètre une URL, et ensuite cette fonction fait une " tonne de traitement " pour récupérer certaine information, transformer la donnée en utilisant les différentes fonctions de chaînes...
    Certainement qu'un bon codeur pourra gagner quelques temps de traitement d'une URL, disons par exemple que le temps se réduit à 5 sec pour une URL.

    J'aurai toujours cette problématique du nombre d'URL à traiter (soyons fou 100 000 ) URL.

    Cela devient très très compliqué.

  10. #10
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 754
    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 754
    Par défaut
    Citation Envoyé par frutz Voir le message
    Certainement qu'un bon codeur pourra gagner quelques temps de traitement d'une URL, disons par exemple que le temps se réduit à 5 sec pour une URL.
    A priori, la récupération d'une URL retourne un texte HTML et vous avez des bibliothèques "optimisées" pour aller y récupérer des informations dedans.

    Après rendez vous compte qu'allez récupérer le HTML associé à une URL est une opération qui globalement "attend" alors que mouliner l'intérieur pour en extraire... c'est des "calculs". Et on ne va pas optimiser l'un de la même façon que l'autre.

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

  11. #11
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 840
    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 840
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par frutz Voir le message
    Dans mon script j'utiliser une fonction data qui prend en paramètre une URL, et ensuite cette fonction fait une " tonne de traitement " pour récupérer certaine information, transformer la donnée en utilisant les différentes fonctions de chaînes...
    Certainement qu'un bon codeur pourra gagner quelques temps de traitement d'une URL, disons par exemple que le temps se réduit à 5 sec pour une URL.
    Peut-être alors s'orienter vers ce "une tonne de traitement"... Par exemple les regex peuvent offrir de gros raccourcis dans les traitements de chaines...
    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]

  12. #12
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par Sve@r Voir le message
    D'autant plus avec ce list.append() qui est tout sauf optimal (la liste en intension aurait au-moins évité cette instruction).
    .
    C'est vraiment plus rapide ?
    Dans l'exemple qui suit, on dirait que l'intension demande plus d'opération à cause du "désassemblage" (aucune idée de ce que c'est).
    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
    >>> def A():
    	m = [x for x in range(500)]
     
     
    >>> l = []
    >>> def B():
    	for x in range(500):
    		l.append(x)
     
     
    >>> import dis
    >>> dis.dis(A)
      2           0 LOAD_CONST               1 (<code object <listcomp> at 0x0000023D220250E0, file "<pyshell#8>", line 2>)
                  2 LOAD_CONST               2 ('A.<locals>.<listcomp>')
                  4 MAKE_FUNCTION            0
                  6 LOAD_GLOBAL              0 (range)
                  8 LOAD_CONST               3 (500)
                 10 CALL_FUNCTION            1
                 12 GET_ITER
                 14 CALL_FUNCTION            1
                 16 STORE_FAST               0 (m)
                 18 LOAD_CONST               0 (None)
                 20 RETURN_VALUE
     
    Disassembly of <code object <listcomp> at 0x0000023D220250E0, file "<pyshell#8>", line 2>:
      2           0 BUILD_LIST               0
                  2 LOAD_FAST                0 (.0)
            >>    4 FOR_ITER                 8 (to 14)
                  6 STORE_FAST               1 (x)
                  8 LOAD_FAST                1 (x)
                 10 LIST_APPEND              2
                 12 JUMP_ABSOLUTE            4
            >>   14 RETURN_VALUE
    >>> dis.dis(B)
      2           0 LOAD_GLOBAL              0 (range)
                  2 LOAD_CONST               1 (500)
                  4 CALL_FUNCTION            1
                  6 GET_ITER
            >>    8 FOR_ITER                14 (to 24)
                 10 STORE_FAST               0 (x)
     
      3          12 LOAD_GLOBAL              1 (l)
                 14 LOAD_METHOD              2 (append)
                 16 LOAD_FAST                0 (x)
                 18 CALL_METHOD              1
                 20 POP_TOP
                 22 JUMP_ABSOLUTE            8
            >>   24 LOAD_CONST               0 (None)
                 26 RETURN_VALUE

  13. #13
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 754
    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 754
    Par défaut
    Citation Envoyé par LeNarvalo Voir le message
    C'est vraiment plus rapide ?
    C'est pas le nombre d'instructions qui fera que c'est plus ou moins rapide mais le temps que çà met et qu'on peut mesurer avec timeit.
    Et parfois, c'est plus lent.

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

  14. #14
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 840
    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 840
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par frutz Voir le message
    J'aurai toujours cette problématique du nombre d'URL à traiter (soyons fou 100 000 ) URL.

    Cela devient très très compliqué.
    J'ai réfléchi à un truc
    Première étape: essayer de déterminer ce qui fait ce goulot d'étranglement dont parle wiztricks. Est-ce le téléchargement ou le traitement. Donc je te propose de télécharger 30 URL dans une grosse string (ou une liste de 30 strings). Tu regardes le temps que ça prend.
    Ensuite tu fais tes "tonnes de traitement" mais tu les fais sur les strings téléchargées et non pas sur les URL. Et là encore, un petit chrono avec time.perf_counter() ça devrait le faire.
    Là on pourra voir sur ces 30 secondes qui fait quoi.

    Ensuite, un second test facile à faire pour voir si des solutions de parallélisation seraient efficaces: tu prends ton source et tu le programmes pour juste 30 URL. Et tu le lances. Ok ça devrait prendre 15 minutes.
    Puis tu le copies en deux sources X et Y. Dans X tu ne mets que 15 URL et dans Y tu mets les 15 autres. Et tu lances les deux à la fois (deux fenêtres de travail). Et là tu verras si pour l'ensemble ça prend 7minutes30 (ok super) ou 14minutes45 (parallélisation inutile).

    Une hypothèse : c'est le téléchargement qui prend du temps. Ca semblerait plutôt logique (il n'y a qu'un câble réseau). Donc une solution intermédiaire serait de découper le programme en deux parties. La première qui télécharge et stocke le tout dans par exemple une bdd sqlite, et la seconde qui traite le contenu de la bdd.
    Déjà le téchargement pourrait se faire à intervalles plus ou moins long selon que les URL évoluent plus ou moins rapidement et l'importance que l'on accorde à la différence entre "ce qui est" et "ce qu'on traite". Et ensuite la parallélisation pourrait être faite sur le simple traitement des datas où là ça peut s'avérer utile.
    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]

Discussions similaires

  1. Optimisation code trop lent
    Par Pynouz dans le forum Windows Forms
    Réponses: 3
    Dernier message: 27/02/2013, 14h44
  2. Code trop lent à optimiser
    Par deuche dans le forum Macros et VBA Excel
    Réponses: 4
    Dernier message: 12/10/2011, 16h18
  3. Optimisation de requêtes trop lentes..
    Par Nevrosl dans le forum Requêtes
    Réponses: 5
    Dernier message: 11/03/2010, 13h38
  4. Code trop lent: recuperation de donnees dans un autre classeur
    Par nianko dans le forum Macros et VBA Excel
    Réponses: 2
    Dernier message: 05/01/2010, 10h43
  5. [Eclipse] Editeur de code trop lent
    Par Benzeghiba dans le forum Eclipse Java
    Réponses: 6
    Dernier message: 10/11/2005, 14h02

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