我正在尝试使用Python Profiler来加快代码。我已经能够识别几乎所有时间都花在的特定功能,但是我无法弄清楚时间在哪里。

在下面,我有配置文件输出,这表明“附录Baplot”是主要的罪魁祸首,并且消耗了将近116秒。在下面的此外,我有“ appendballot”的代码。

我无法从配置文件输出中找出“附录ballot”的哪一部分,我需要优化,因为下一个最高时间的条目小于一秒钟。我敢肯定,你们中的许多人都可以从我的代码中告诉我,但是我想了解如何从配置文件输出中获取这些信息。任何帮助将不胜感激。

配置文件输出:

  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)

代码:

  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)
有帮助吗?

解决方案

牧师可以那样。我使用的方法是 这个. 。它立即成为问题的核心。

其他提示

是的,我也遇到了同样的问题。

我知道解决此问题的唯一方法是将您的大功能包裹在几个较小的函数调用中。这将允许调查员考虑每个较小的函数调用。

有趣的是,这样做的过程(无论如何,对我来说)使效率低下的地方很明显,所以我什至不必经营探险师。

我已经看了您的代码,看来您会在“检查”的一部分或在跳跃前向前看,进行大量函数调用和属性查找。您还拥有许多专门跟踪相同条件的代码,即许多代码来创建“唯一” ID。

与其尝试为每个选票分配某种唯一的字符串,不只是使用投票数(整数编号吗?)

现在,您可以使用词典(unique ballotids)映射节目和实际投票对象。

该过程可能是这样的:

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)

您可能能够通过使用默认设备(来自Collections Module)来处理对词典缺少给定键的一些担忧。 收集文档

编辑 为了完整性,我将包括默认数据的示例使用:

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

我用过 这个装饰师 在我的代码中,它帮助我进行了调音工作。

我会说您要将您的功能分为较小的功能,从而支持Fragsworth。

话虽如此,您正在正确阅读输出:搅拌器是值得关注的。

现在,您的放缓可能是:

由于似乎有100000个呼叫AppendBallot的电话,而且没有明显的循环,我建议您在您的断言中。因为您正在执行:

assert(ballotID not in self.ballotIDs)

这实际上将充当循环。因此,您第一次调用此功能时,它将通过(可能为空的)数组迭代,然后断言是否找到了值。它将第100000次迭代整个阵列。

实际上,这里可能有一个错误:如果删除了投票,则添加的下一个投票将具有与上次添加的投票相同的ID(除非已删除的ID)。我认为您最好使用一个简单的计数器。这样,每次添加选票时,都可以将其递增。另外,您可以使用UUID获得唯一的ID。

另外,如果您正在寻找某种持久性,请使用ORM,并让它进行ID生成,并为您进行独特的检查。

您在这条小块的代码中遇到了两个问题:

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

首先,似乎self.ballids是一个列表,因此断言语句将导致二次行为。由于您根本没有为数据结构提供任何文档,因此不可能具有规定性,但是如果外观没关系,则可以使用集合而不是列表。

其次,逻辑(在没有关于投票的全部内容的文档中,以及什么不是单个的Boldid Arg的含义)似乎很严重:

obj.appendBallot(ballota, 2) # self.ballotIDs -> [2]
obj.appendBallot(ballotb)    # self.ballotIDs -> [2, 1]
obj.appendBallot(ballotc)    # wants to add 2 but triggers assertion

其他的建议:

代替 adict.has_key(key), , 利用 key in adict - 它更快,看起来更好。

您可能想考虑查看数据结构...它们似乎有些巴洛克式;构建它们可能有相当大的CPU时间。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top