gpt4 book ai didi

python - 字符串性能 - Windows 10 与 Ubuntu 下的 Python 2.7 与 Python 3.4

转载 作者:太空狗 更新时间:2023-10-29 21:49:01 26 4
gpt4 key购买 nike

用例
一个简单的函数,用于检查特定字符串是否位于另一个字符串中的 3 倍数位置(参见此处的 real world example,查找终止密码子在 DNA 序列中)。

函数
sliding_window:将长度为 3 的字符串与搜索字符串进行比较,如果相同则向前移动 3 个字符。
incremental_start:尝试查找搜索字符串,如果找到的位置不是 3 的倍数,则尝试找到找到位置之后的下一个位置。

请注意:示例数据只是为了确保每个函数都必须遍历完整的字符串,性能与真实数据或随机数据相似。

结果

  • Python 2.7:通过使用 Python2.7 中的函数 incremental_start,可以将初始的 sliding_window 函数提高约 39 倍Windows 10。Ubuntu 上的性能提升略有下降,~34x、~37x、~18x(VM、AWS、 native ),但仍在同一范围内。
  • Python 3.4:sliding_window 变得比 Python2.7 慢(在 Windows 上为 1.8x,在所有 Ubuntu 上为 1.4x resp. 1.5x),但是 incremental_start 性能在所有 Ubuntu 上下降了 4、5、1.7 倍(VM、AWS、 native ),而在 Windows 上几乎没有变化。
  • Windows vs Ubuntu
    Python2.7:虚拟化的 Ubuntu 需要更少的时间来实现这两个功能(~20-30%),原生 Ubuntu 大约是 25% incremental_start 较慢,而 sliding_window 快 40%。
    Python3:sliding_window 函数需要更少的时间来完成 (~50%),而 incremental_start 变慢了~2-3 倍.

问题

  • 是什么导致 Python 2 与 Python 3 在 Linux 和 Windows 上的性能差异?
  • 如何预测此类行为并调整代码以获得最佳性能?

代码

import timeit

text = 'ATG' * 10**6
word = 'TAG'

def sliding_window(text, word):
for pos in range(0, len(text), 3):
if text[pos:pos + 3] == word:
return False
return True

def incremental_start(text, word):
start = 0
while start != -1:
start = text.find(word, start + 1)
if start % 3 == 0:
return False
return True

#sliding window
time = timeit.Timer(lambda: sliding_window(text, word), setup='from __main__ import text, word').timeit(number=10)
print('%3.3f' % time)

#incremental start
time = timeit.Timer(lambda: incremental_start(text, word), setup='from __main__ import text, word').timeit(number=500)
print('%3.3f' % time)

表格

Ubuntu vs Windows    VM     AWS    Native   
Python2.7-Increment 79% 73% 126%
Python2.7-Sliding 70% 70% 60%
Python3.4-Increment 307% 346% 201%
Python3.4-Sliding 54% 59% 48%

Py2 vs 3 Windows VM AWS Native
Increment 105% 409% 501% 168%
Sliding 184% 143% 155% 147%

Absolute times in seconds
Win10 Ubuntu AWS Native
Py2.7-Increment 1.759 1.391 1.279 2.215
Py2.7-Sliding 1.361 0.955 0.958 0.823

Py3.4-Increment 1.853 5.692 6.406 3.722
Py3.4-Sliding 2.507 1.365 1.482 1.214

详情
Windows 10: native Windows、32 位 Python 3.4.3 或 2.7.9、i5-2500、16GB RAM
Ubuntu虚拟机:14.04,运行在Windows主机上,64位Python 3.4.3,Python 2.7.6,4核,4GB RAM
AWS:14.04,AWS 微实例,64 位 Python 3.4.3,Python 2.7.6
native Ubuntu:14.04、64 位 Python 3.4.3、Python 2.7.6、i5-2500、16GB 内存 [与 Win10 机器相同]


更新

根据 Ingaz 的建议,使用了 xrangebytes,性能略有提高,但在使用 Python3.4 的 Ubuntu 上性能仍然大幅下降。罪魁祸首似乎是 find ,当 Ubuntu 和 Py3.4 结合使用时它要慢得多(与从源代码编译的 Py3.5 相同)。这似乎依赖于 Linux 风格,在 Debian Py2.7 和 Py3.4 上执行相同,在 RedHat Py2.7 上比 Py3.4 快得多。
为了更好地比较 Py3.4 现在在 Windows10 和 Ubuntu 的 64 位中使用。 Win10 上仍然使用 Py27。

import timeit, sys

if sys.version_info >= (3,0):
from builtins import range as xrange

def sliding_window(text, word):
for pos in range(0, len(text), 3):
if text[pos:pos + 3] == word:
return False
return True

def xsliding_window(text, word):
for pos in xrange(0, len(text), 3):
if text[pos:pos + 3] == word:
return False
return True

def incremental_start(text, word):
start = 0
while start != -1:
start = text.find(word, start + 1)
if start % 3 == 0:
return False
return True

text = 'aaa' * 10**6
word = 'aaA'
byte_text = b'aaa' * 10**6
byte_word = b'aaA'

time = timeit.Timer(lambda: sliding_window(text, word), setup='from __main__ import text, word').timeit(number=10)
print('Sliding, regular: %3.3f' % time)

time = timeit.Timer(lambda: incremental_start(text, word), setup='from __main__ import text, word').timeit(number=500)
print('Incremental, regular: %3.3f' % time)

time = timeit.Timer(lambda: sliding_window(byte_text, byte_word), setup='from __main__ import byte_text, byte_word').timeit(number=10)
print('Sliding, byte string: %3.3f' % time)

time = timeit.Timer(lambda: incremental_start(byte_text, byte_word), setup='from __main__ import byte_text, byte_word').timeit(number=500)
print('Incremental, bytes: %3.3f' % time)

time = timeit.Timer(lambda: xsliding_window(byte_text, byte_word), setup='from __main__ import byte_text, byte_word').timeit(number=10)
print('Sliding, xrange&bytes: %3.3f' % time)

time = timeit.Timer(lambda: text.find(word), setup='from __main__ import text, word').timeit(number=1000)
print('simple find in string: %3.3f' % time)


Win10-py27 Wi10-py35 VM-py27 VM-py34
1.440 2.674 0.993 1.368
1.864 1.425 1.436 5.711
1.439 2.388 1.048 1.219
1.887 1.405 1.429 5.750
1.332 2.356 0.772 1.224
3.756 2.811 2.818 11.361

最佳答案

虽然您测量的是相同代码的速度,但您的代码中的结构是不同的。

一个。 range 在 2.7 中是 type 'list',range 在 3.4 中是 class 'range'

B. 'ATG' * 10**6 在 2.7 中是一个字节字符串,在 3.4 中是和 unicode 字符串

如果出现以下情况,您可以尝试生成更兼容的结果:a) 对 2.7 变体使用 xrange,b) 在两个示例中使用 bytes 字符串:b'ATG' 或 unicode两个示例中的字符串。

更新

我怀疑性能差异源于主要因素:a) 32 位与 64 位,b) C 编译器。

所以,我做了以下测试:

  1. ActiveState Python 2.7.10 32 位
  2. ActiveState Python 2.7.10 64 位
  3. 官方发布Python 2.7.11 32bit
  4. 官方发布 Python 2.7.11 64bit
  5. Python 2.7.6 64 位 Ubuntu on Windows 10
  6. pypy-5.1.1-win32

我的预期

我预计:

  • 64位版本会比较慢
  • ActiveState会快一点
  • PyPy 速度更快
  • Windows 10 上的 Ubuntu - ???

结果

Test                    as32b   as64b   off32b   off64b  ubw64b  pypy5.1.1
Sliding, regular: 1.232 1.230 1.281 1.136 0.951 0.099
Incremental, regular: 1.744 1.690 2.219 1.647 1.472 2.772
Sliding, byte string: 1.223 1.207 1.280 1.127 0.926 0.101
Incremental, bytes: 1.720 1.701 2.206 1.646 1.568 2.774
Sliding, xrange&bytes: 1.117 1.102 1.162 0.962 0.779 0.109
simple find in string: 3.443 3.412 4.607 3.300 2.487 0.289

Windows 10 上的赢家是......由 GCC 4.8.2 为 Linux 编译的 Ubuntu Python!

这个结果完全出乎我的意料。

32 与 64:变得无关紧要。

PyPy:一如既往的 super 快,除非不是。

我无法解释这个结果,OP 问题变得不像看起来那么简单。

关于python - 字符串性能 - Windows 10 与 Ubuntu 下的 Python 2.7 与 Python 3.4,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37052139/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com