python - 为什么使用属性而不是方法可以显着提高 Python 速度

标签 python regex performance

我一直在试验一个进行模式匹配的类。我的类(class)看起来像这样:

class Matcher(object):
  def __init__(self, pattern):
    self._re = re.compile(pattern)

  def match(self, value):
    return self._re.match(value)

总而言之,我的脚本运行大约需要 45 秒。作为实验,我将代码更改为:

class Matcher(object):
  def __init__(self, pattern):
    self._re = re.compile(pattern)
    self.match = self._re.match

运行此脚本需要 37 秒。无论我重复这个过程多少次,我都看到同样显着的性能提升。通过 cProfile 运行它会显示如下内容:

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
 46100979   14.356    0.000   14.356    0.000 {method 'match' of '_sre.SRE_Pattern' objects}
 44839409    9.287    0.000   20.031    0.000 matcher.py:266(match)

到底为什么 match 方法会在运行时间上增加 9.2 秒? 最令人沮丧的部分是我试图重新创建一个简单的案例,但未能成功。我在这里错过了什么? 我的简单测试用例有一个错误!现在它模仿我所看到的行为:

import re
import sys
import time

class X(object):
  def __init__(self):
    self._re = re.compile('.*a')

  def match(self, value):
    return self._re.match(value)

class Y(object):
  def __init__(self):
    self._re = re.compile('ba')
    self.match = self._re.match

inp = 'ba'
x = X()
y = Y()

sys.stdout.write("Testing with a method...")
sys.stdout.flush()
start = time.time()
for i in range(100000000):
  m = x.match(inp)
end = time.time()
sys.stdout.write("Done: "+str(end-start)+"\n")

sys.stdout.write("Testing with an attribute...")
sys.stdout.flush()
start = time.time()
for i in range(100000000):
  m = y.match(inp)
end = time.time()
sys.stdout.write("Done: "+str(end-start)+"\n")

输出:

$ python speedtest.py 
Testing with a method...Done: 50.6646981239
Testing with an attribute...Done: 35.5526258945

作为引用,使用 pyp 时两者都快,但在使用属性而不是方法运行时仍然显示出显着的 yield :

$ pypy speedtest.py 
Testing with a method...Done: 6.15996003151
Testing with an attribute...Done: 3.57215714455

最佳答案

这可能主要是附加函数调用的开销。调用 Python 函数在性能方面相对昂贵,因为需要设置额外的堆栈框架等。这是一个演示类似性能的简单示例:

>>> timeit.timeit("f()", "g = (lambda: 1); f = lambda: g()")
0.2858083918486847
>>> timeit.timeit("f()", "f = lambda: 1")
0.13749289364989004

在您的方法中进行两次额外的属性查找也会产生额外的成本:在 self 上查找 _re,然后查找 match在那个 _re 对象上。但是,这可能是一个较小的组件,因为 Python 中的字典查找速度非常快。 (我上面的 timeit 示例显示了相当差的性能,即使在双重调用版本中只有一个额外的名称查找也是如此。)

关于python - 为什么使用属性而不是方法可以显着提高 Python 速度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12324272/

相关文章:

sql - 这是使用嵌入式 SQL 而不是存储过程的有效好处吗?

python - 如何使用 scikit learn 向量化标记的二元组?

python - Django Rest 应用程序未正确使用媒体根来提供图像

r - R data.table 逐行操作的首选性能过程?

regex - Hive:在列名中使用 Concat

java - 使用正则表达式接受包含字母的字符串

mysql - SQLite 真的比 MySQL 快吗?

python - 操作系统错误 : [Errno 20] Not a directory, .DS_Store

python - 从特定位置提取数据,无论空格如何

python - 在标记自定义迷你格式时正确考虑多个反斜杠