9
votes

Profilant des générateurs de python

J'adapte une application qui utilise de lourdes générateurs pour produire ses résultats pour fournir une interface Web web.py.

Jusqu'à présent, je pourrais envelopper l'appel à la boucle et les déclarations productrices de sortie Dans une fonction et appelez celui utilisant cprofile.run () code> ou runctx () code>. Conceptuellement: p> xxx pré>

dans web.py, je dois envelopper la manière suivante, car je veux produire immédiatement la sortie du calcul potentiellement longuant dans chaque étape d'itération en utilisant Rendement CODE>: P>

class index:
    def GET(self):
        for value in generator():
            yield make_pretty_html(value)


2 commentaires

Voulez-vous simplement mesurer l'appel de la fonction entière au lieu d'une seule itération? Comme dans CProfile.Run ('Liste (Index (). Obtenez ())') ?


En substance, c'est ce que la boucle accomplie. Le problème ici est que je n'ai pas de contrôle sur les appels vers get () , il est géré par web.py . De plus, je ne pense pas que la production serait produite de cette façon (en utilisant la valeur de retour).


3 Réponses :


0
votes

Pouvez-vous simplement utiliser Time.time () pour profiler les pièces qui vous intéressent? Obtenez juste l'heure actuelle et soustrayez de la dernière fois que vous avez effectué une mesure.


2 commentaires

Je reçois déjà le timing total, mais "le traitement a pris 5,382 secondes" n'est pas suffisamment spécifique pour trouver des goulots d'étranglement de performances. J'utilise une chaîne de générateurs assez importante et ramifiée en interne et destinée à stocker les entrées de l'utilisateur et les performances résultantes pour une analyse ultérieure. J'ai plusieurs fonctions qui prennent une moyenne de 0,000 secondes chaque appel, mais pourraient être appelés dizaines de milliers de fois.


Dans ce cas, vous pouvez avoir un compteur entier pour chaque exécution de ces fonctions et effectuer uniquement une mesure toutes les 1000e exécution? Vous pouvez mesurer des morceaux de code de cette façon et réduire les goulots d'étranglement. Je me rends compte que cela peut être un peu fastidieux, en fonction du code.



2
votes

On dirait que vous essayez de profiler chaque appel à «Suivant» sur le générateur? Si tel est le cas, vous pouvez envelopper votre générateur dans un générateur de profilage. Quelque chose comme ça, où la partie commentée envoiera les résultats à un journal ou une base de données. xxx

puis au lieu d'instantifier votre générateur comme générateur vous Utilisez iter_profiler (générateur ())


3 commentaires

Sinon, vous pouvez appliquer une version modifiée de celui-ci en tant que décorateur à la définition du générateur.


Fondamentalement, vous avez raison. Je compte déjà les millisecondes entre avant et après le pour en boucle de mon deuxième exemple d'origine, donc j'ai déjà cette information (bien que je compte un peu plus que ce que vous le feriez, mais quelques millis Don ' la matière). Cependant, je me soucie davantage des "points chauds" dans mon code (où est-ce que le temps de calcul va mourir?) Que exactement lequel des dizaines de résultats ont pris plus de temps que les autres. Par conséquent, j'espérais une solution basée sur un Profile / CProfile (qui ne génère pas un rapport par résultat). S'il y a un moyen de fusionner des rapports de profileur, ce serait la voie à suivre.


Pour quiconque en regardant cette solution dans Python3.x, notez que les générateurs n'ont pas de long ont une méthode suivante () , utilisez la fonction libre ( Stackoverflow.com/questions/21622193/ ... ) à la place. Ceci est fait dans la réponse ci-dessus.



7
votes

J'ai enfin trouvé une solution. Valeur de retour du profilage via ici .

import cProfile
import pstats
import glob
import math

def gen():
    for i in range(1, 10):
        yield math.factorial(i)

class index(object):
    def GET(self):
        p = cProfile.Profile()

        it = gen()
        while True:
            try:
                nxt = p.runcall(next, it)
            except StopIteration:
                break
            print nxt

        p.print_stats()

index().GET()


0 commentaires