【问题标题】:Python profiling, imports (and specially __init__) is what seems to take the most timePython 分析、导入(尤其是 __init__)似乎花费了最多时间
【发布时间】:2018-11-06 08:08:35
【问题描述】:

我有一个似乎运行缓慢的脚本,我使用 cProfile(和可视化工具 KCacheGrind)对其进行了分析

似乎占用了几乎 90% 的运行时间的是导入序列,尤其是 _ _ init _ _.py 文件的运行...

这里是 KCacheGrind 输出的截图(抱歉附上图片...)

我不太熟悉 python 中的导入序列是如何工作的,所以也许我有些困惑......我还在我的每个定制包中放置了_ _ init _ _.py 文件,不确定这是否是我应该拥有的完成。

无论如何,如果有人有任何提示,不胜感激!


编辑:功能按自身排序时的附加图片:


EDIT2:

这里附上代码,以便回答者更清楚:

from strategy.strategies.gradient_stop_and_target import make_one_trade

from datetime import timedelta, datetime
import pandas as pd
from data.db import get_df, mongo_read_only, save_one, mongo_read_write, save_many
from data.get import get_symbols

from strategy.trades import make_trade, make_mae, get_prices, get_signals, \
    get_prices_subset
#from profilehooks import profile


mongo = mongo_read_only()


dollar_stop = 200
dollar_target = 400
period_change = 3


signal = get_df(mongo.signals.signals, strategy = {'$regex' : '^indicators_group'}).iloc[0]


symbol = get_symbols(mongo, description = signal['symbol'])[0]


prices = get_prices(
    signal['datetime'], 
    signal['datetime'].replace(hour = 23, minute = 59),
    symbol,
    mongo)


make_one_trade(
    signal, 
    prices, 
    symbol,             
    dollar_stop,
    dollar_target,
    period_change)

函数 get_prices 只是从 mongo db 数据库中获取数据,而 make_one_trade 使用 pandas 进行简单的计算。这在我的项目中的其他任何地方都不会出现问题。


EDIT3:

当我在“视图”选项卡中选择“检测周期”选项时,这里是 Kcache 研磨屏幕:

这是否真的意味着我自己创建的包中确实存在循环导入,需要花费所有时间才能解决?

【问题讨论】:

  • 没有。您将 聚合时间 与方法本身所花费的时间混为一谈。 __init__ 调用其他方法,这些方法一起需要很多时间。
  • 我不太清楚你在这里问什么?
  • @MartijnPieters 通常点击图中的函数会显示子函数,但这里似乎是某种循环,并且所有函数都标记为 ,所以它没有告诉我什么需要时间...
  • @jimbasquiat:那是因为<frozen importlib.*> 路径都以关键路径部分的本机 C 实现结束,cProfile 不会获取这些路径。你真的想过滤掉那些。
  • @StephenRauch 我不明白如何在此处继续进行分析,因为箭头会循环,而且似乎导入需要时间。如果有人对这种情况有过一些经验,我会很高兴知道如何继续了解什么是需要时间的,如何发现它。

标签: python profiling


【解决方案1】:

没有。您将 累积时间 与花费在 __init__.py 文件本身的顶级代码中的时间混为一谈。顶级代码调用其他方法,这些方法一起需要很多时间。

查看 self 列,找出所有时间都花在了哪里。另见What is the difference between tottime and cumtime in a python script profiled with cProfile?incl.栏为累计时间,self为总时间。

我只是过滤掉所有<frozen importlib.*> 条目; Python 项目已经确保优化了这些路径。

但是,您的第二个屏幕截图确实显示,在您的分析运行中,您的 Python 代码忙于加载要导入的模块的字节码(marshal module 提供了 Python 字节码序列化实现)。 Python程序除了导入模块什么都不做,没有做其他工作,或者它正在使用某种形式的动态导入来加载大量模块,或者忽略正常的模块缓存并重复重新加载相同的模块.

您可以使用 Python 3.7 的新 -X importtime command-line switch 来分析导入时间,或者您可以使用专用的 import-profiler 来找出导入需要这么长时间的原因。

【讨论】:

  • 我重新上传了图片以更好地显示箭头指向的位置。我了解 tottime 和 cumtime 之间的区别,我的问题是这里的箭头从不指向实际函数,而是循环运行,并且似乎只在脚本的“导入”部分花费时间 - 只是添加了一个图片功能按自我排序以更好地解释我的问题
  • @jimbasquiat:这确实表明您的程序在导入时大部分时间都在加载字节码缓存(marshal 模块用于 Python 字节码的序列化/反序列化)。在这一点上,我不得不问:除了导入模块之外,您的代码是否做任何事情?它是否使用任何类型的忽略sys.modules 缓存的动态模块加载?
  • 我编辑了问题以显示/简要解释代码并显示额外的 KCacheGrind 屏幕。再次感谢您的帮助!
  • 所有代码运行..我可以在分析日志中找到函数 get_prices 和 make_one_trade 的名称 - 但它们运行时间很短,这就是为什么它完全被淹没在巨大的导入所花费的时间。我是否有可能在我的项目中创建 init.py 文件时犯了错误,或者其他可能影响我的自定义创建包加载时间的事情?我之前已经在同一个项目中遇到过这个问题
  • @jimbasquiat:你的代码比那个文件大得多,data 包有什么作用?这很快就变得太宽泛了,无法回答;我不能在这里帮你调试一个完整的项目。
猜你喜欢
  • 2020-11-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-05-10
  • 2015-08-02
  • 2017-02-15
  • 2020-07-23
相关资源
最近更新 更多