Python生成器性能分析

9 投票
3 回答
2676 浏览
提问于 2025-04-16 03:18

我正在调整一个应用程序,这个程序大量使用生成器来产生结果,现在我想给它加一个 web.py 的网页接口。

到目前为止,我已经把 for 循环和输出的部分放进一个函数里,然后用 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)

有没有办法像第一个例子那样,对所有生成器的调用进行性能分析,而在第二种用法中也能做到这一点呢?

3 个回答

0

你可以直接用 time.time() 来测量你感兴趣的部分吗?只需要获取当前的时间,然后减去你上次测量的时间就可以了。

2

听起来你是想要记录每次调用生成器的'next'方法的情况?如果是这样的话,你可以把你的生成器放在一个专门用来记录的生成器里面。可以像这样做,注释掉的部分是用来把结果发送到日志或者数据库里的。

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()) 来创建。

7

我终于找到了解决办法。关于使用 cprofile 的返回值,可以查看这里。

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

我还可以通过给文件命名不同的名字,合并多个这样的分析结果,具体可以参考 文档,然后把它们存起来一起分析。

撰写回答