了解Python配置文件输出

gae*_*fan 7 python profile profiling

我正在尝试使用Python分析器来加速我的代码.我已经能够确定几乎所有时间花在的特定功能,但我无法弄清楚该功能在何时花费的时间.

下面我有个人资料输出,它显示"appendBallot"是罪魁祸首,消耗将近116秒.下面,我有"appendBallot"的代码.

我无法从配置文件输出中找出,我需要优化"appendBallot"的哪一部分,因为下一个最高时间条目不到一秒.我相信很多人只能从我的代码中告诉我,但我想了解如何从配置文件输出中获取该信息.任何帮助将不胜感激.

档案输出:

  ncalls  tottime  percall  cumtime  percall filename:lineno(function)
       1    0.000    0.000  116.168  116.168 <string>:1(<module>)
       1    0.001    0.001  116.168  116.168 {execfile}
       1    0.003    0.003  116.167  116.167 foo.py:1(<module>)
       1    0.000    0.000  116.139  116.139 ballots.py:330(loadKnown)
       1    0.000    0.000  116.109  116.109 plugins.py:148(load)
       1    0.196    0.196  116.108  116.108 BltBallotLoader.py:37(loadFile)
  100000  114.937    0.001  115.912    0.001 ballots.py:133(appendBallot)
  100000    0.480    0.000    0.790    0.000 ballots.py:117(newBallot)
  316668    0.227    0.000    0.310    0.000 ballots.py:107(getNumCandidates)
417310/417273    0.111    0.000    0.111    0.000 {len}
  200510    0.071    0.000    0.071    0.000 {method 'append' of 'list' objects}
   99996    0.045    0.000    0.045    0.000 {method 'add' of 'set' objects}
  100000    0.042    0.000    0.042    0.000 {method 'has_key' of 'dict' objects}
       1    0.000    0.000    0.030    0.030 plugins.py:202(getLoaderPluginClasses)
       1    0.000    0.000    0.030    0.030 plugins.py:179(getPluginClasses)
       1    0.000    0.000    0.030    0.030 plugins.py:205(getLoaderPluginClass)
       3    0.016    0.005    0.029    0.010 {__import__}
       1    0.022    0.022    0.025    0.025 ballots.py:1(<module>)
       1    0.010    0.010    0.013    0.013 BltBallotLoader.py:1(<module>)
       7    0.000    0.000    0.003    0.000 re.py:227(_compile)
Run Code Online (Sandbox Code Playgroud)

码:

  def appendBallot(self, ballot, ballotID=None):
    "Append a ballot to this Ballots object."

    # String representation of ballot for determining whether ballot is unique
    ballotString = str(list(ballot))

    # Ballot as the appropriate array to conserve memory
    ballot = self.newBallot(ballot)

    # Assign a ballot ID if one has not been given
    if ballotID is None:
      ballotID = len(self.ballotIDs)
    assert(ballotID not in self.ballotIDs)
    self.ballotIDs.append(ballotID)

    # Check to see if we have seen this ballot before
    if self.uniqueBallotsLookup.has_key(ballotString):
      i = self.uniqueBallotsLookup[ballotString]
      self.uniqueBallotIDs[i].add(ballotID)
    else:
      i = len(self.uniqueBallots)
      self.uniqueBallotsLookup[ballotString] = i
      self.uniqueBallots.append(ballot)
      self.uniqueBallotIDs.append(set([ballotID]))
    self.ballotOrder.append(i)
Run Code Online (Sandbox Code Playgroud)

Fra*_*rth 7

是的,我也遇到过同样的问题.

我知道解决这个问题的唯一方法是将大函数包装成几个较小的函数调用.这将允许探查器考虑每个较小的函数调用.

有趣的是,这样做的过程(对我而言,无论如何)使得低效率显而易见,因此我甚至不必运行分析器.


Sim*_*rds 5

我已经看过你的代码,看起来你做了很多函数调用和属性查找,作为你'检查'的一部分,或者在跳跃之前向前看.您还有许多专用于跟踪相同条件的代码,即用于创建"唯一"ID的许多代码.

而不是试图为每个选票分配某种独特的字符串,你不能只使用ballotID(一个整数吗?)

现在你可以有一个字典(uniqueBallotIDs)映射ballotID和实际的选票对象.

过程可能是这样的:

def appendBallot(self, ballot, ballotID=None):
   if ballotID is None:
       ballotID = self._getuniqueid() # maybe just has a counter? up to you.
   # check to see if we have seen this ballot before.
   if not self._isunique(ballotID):
       # code for non-unique ballot ids.
   else:
       # code for unique ballot ids.

   self.ballotOrder.append(i)
Run Code Online (Sandbox Code Playgroud)

您可以通过使用defaultdict(来自collections模块)来处理一些关于字典缺少给定键的担忧.收集文档

编辑完整性我将包含defaultdict的示例用法:

>>> from collections import defaultdict            

>>> ballotIDmap = defaultdict(list)
>>> ballotID, ballot = 1, object() # some nominal ballotID and object.
>>> # I will now try to save my ballotID.
>>> ballotIDmap[ballotID].append(ballot)
>>> ballotIDmap.items()
[(1, [<object object at 0x009BB950>])]
Run Code Online (Sandbox Code Playgroud)


Mat*_*kel 5

我将支持 Fragsworth,说您希望将您的功能拆分为更小的功能。

话虽如此,您正在正确读取输出:tottime 是值得关注的。

现在你的放缓可能是:

由于似乎有 100000 次调用 appendBallot,并且没有任何明显的循环,我建议它在您的断言中。因为你正在执行:

assert(ballotID not in self.ballotIDs)
Run Code Online (Sandbox Code Playgroud)

这实际上将充当一个循环。因此,第一次调用这个函数时,它会遍历一个(可能是空的)数组,然后断言是否找到了值。第 100000 次它将遍历整个数组。

这里实际上有一个可能的错误:如果删除了一个选票,那么添加的下一个选票将与上一个添加的选票具有相同的 ID(除非那是被删除的)。我认为你最好使用一个简单的计数器。这样你就可以在每次添加选票时增加它。或者,您可以使用 UUID 来获取唯一 ID。

或者,如果您正在考虑某种程度的持久性,请使用 ORM,并让它为您进行 ID 生成和唯一检查。


Mik*_*vey 5

探查器可以是这样的。我使用的方法是这样的。它立即触及问题的核心。