将 cProfile 结果保存到可读的外部文件

新手上路,请多包涵

我正在使用 cProfile 尝试分析我的代码:

 pr = cProfile.Profile()
pr.enable()
my_func()   # the code I want to profile
pr.disable()
pr.print_stats()

但是结果太长,无法在Spyder终端完整显示(看不到运行时间最长的函数调用。。。)。我也尝试使用保存结果

 cProfile.run('my_func()','profile_results')

但输出文件不是人类可读的格式(尝试使用和不使用 .txt 后缀)。

所以我的问题是如何将分析结果保存到人类可读的外部文件中(例如 .txt 格式,所有单词都正确显示)?

原文由 Physicist 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.8k
2 个回答

更新。 您可以使用 io.StringIO() 获取探查器的输出并将其保存到文件中。这是一个例子:

 import cProfile
import pstats
import io

def my_func():
    result = []
    for i in range(10000):
        result.append(i)

    return result

pr = cProfile.Profile()
pr.enable()

my_result = my_func()

pr.disable()
s = io.StringIO()
ps = pstats.Stats(pr, stream=s).sort_stats('tottime')
ps.print_stats()

with open('test.txt', 'w+') as f:
    f.write(s.getvalue())

运行我们的脚本并打开 test.txt 。您将看到可读的结果:

    10002 function calls in 0.003 seconds

   Ordered by: internal time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.002    0.002    0.003    0.003 /path_to_script.py:26(my_func)
    10000    0.001    0.000    0.001    0.000 {method 'append' of 'list' objects}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}

我也可以推荐使用 dump_stats + pstats.Stats 。这是一个如何使用它的例子。文件结构:

 # test_ex.py - just a small web app
import cProfile
import json
from functools import wraps
from flask import Flask

from example.mod1 import func1
from example.mod2 import func2

app = Flask(__name__)

# profiling decorator
def profiling():

    def _profiling(f):
        @wraps(f)
        def __profiling(*rgs, **kwargs):
            pr = cProfile.Profile()
            pr.enable()

            result = f(*rgs, **kwargs)

            pr.disable()
            # save stats into file
            pr.dump_stats('profile_dump')

            return result
        return __profiling
    return _profiling

# demonstration route with profiler
@app.route('/test')
@profiling()
def test():
    counter = func1()
    dict_data = func2()
    result = dict()

    for key, val in dict_data.items():
        result[key] = val + counter

    return json.dumps(result)

if __name__ == '__main__':
    app.run(debug=True, port=8083)

示例 包 - 让我们想象这是某种应用程序逻辑。

 # example.mod1
def func1():
    counter = 0

    for i in range(100000):
        counter += i

    return counter

# example.mod2
def func2():
    res = dict()

    for i in range(300000):
        res['key_' + str(i)] = i

    return res

现在让我们运行服务器( python3 test_ex.py )并打开 http://localhost:8083/test 。几秒钟后你会看到很长的 json。之后,您将在项目文件夹中看到 profile_dump 文件。现在在项目文件夹中运行 python live interpreter 并使用 pstats 打印我们的转储:

 import pstats
p = pstats.Stats('profile_dump')
# skip strip_dirs() if you want to see full path's
p.strip_dirs().print_stats()

统计数据

您还可以轻松排序结果:

 p.strip_dirs().sort_stats('tottime').print_stats()
p.strip_dirs().sort_stats('cumulative').print_stats()
p.strip_dirs().sort_stats().print_stats('mod1')

希望这可以帮助。

原文由 Danila Ganchar 发布,翻译遵循 CC BY-SA 4.0 许可协议

您实际上并不需要 StringIO,因为文件符合流的条件。

 import pstats

with open("profilingStatsAsText.txt", "w") as f:
    ps = pstats.Stats("profilingResults.cprof", stream=f)
    ps.sort_stats('cumulative')
    ps.print_stats()

原文由 Migdalin HasNoLastName 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题