Профилирующие генераторы Python

Я адаптирую приложение, которое сильно использует генераторы для получения своих результатов, чтобы предоставить веб-интерфейс web.py.

До сих пор я мог привязать вызов к циклу и операторам, производящим вывод в функции, и вызвать их с помощью cProfile.run() или runctx(). Концептуально:

def output():
    for value in generator():
        print(value)

cProfile.run('output()')

В web.py, я должен обернуть его следующим образом, так как я хочу немедленно произвести вывод из потенциально долговременного вычисления на каждом шаге итерации с помощью yield:

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

Есть ли способ профилировать все вызовы генератору, как в первом примере, когда он использовался как во втором?

Ответ 1

Наконец-то я нашел решение. Возвращаемое значение профилирования через здесь.

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()

Я также мог бы объединить несколько таких профилирующих результатов (как только я начну давать уникальные имена файлов) с помощью документации и сохранить/проанализировать их вместе.

Ответ 2

Похоже, вы пытаетесь профилировать каждый вызов на "следующий" на генераторе? Если это так, вы можете обернуть ваш генератор в генератор профилирования. Что-то вроде этого, когда часть с комментариями отправляет результаты в журнал или базу данных.

def iter_profiler(itr):
  itr = iter(itr)
  while True:
    try:
      start = time.time()
      value = itr.next()
      end = time.time()
    except StopIteration:
      break
    # do something with (end - stop) times here
    yield value

Затем вместо создания экземпляра генератора в качестве generator() вы использовали бы iter_profiler(generator())

Ответ 3

Можете ли вы просто использовать time.time() для профилирования интересующих вас частей? Просто получить текущее время и вычесть из последнего раза, когда вы сделали измерение.