为什么将连接的字符串分配给 python 中的变量时这么慢?
Why is it so slow when assigning a concatenated string to a variable in python?
如果只是字符串的拼接,直接结束
test_str = "abcdefghijklmn123456789"
str1 = ""
str2 = ""
start = time.time()
for i in range(1, 100001):
str1 = str1 + test_str
str2 = str2 + test_str
if i % 20000 == 0:
print("time(sec) => {}".format(time.time() - start))
start = time.time()
恒定处理时间
time(sec) => 0.013324975967407227
time(sec) => 0.020363807678222656
time(sec) => 0.009979963302612305
time(sec) => 0.01744699478149414
time(sec) => 0.0227658748626709
令人费解的是,将连接的字符串分配给另一个变量会使过程越来越慢。
test_str = "abcdefghijklmn123456789"
str1 = ""
str2 = ""
start = time.time()
for i in range(1, 100001):
str1 = str1 + test_str
# str2 = str2 + test_str
# ↓
str2 = str1
if i % 20000 == 0:
print("time(sec) => {}".format(time.time() - start))
start = time.time()
处理时间会延迟。
time(sec) => 0.36466407775878906
time(sec) => 1.105351209640503
time(sec) => 2.6467738151550293
time(sec) => 5.891657829284668
time(sec) => 9.266698360443115
python2 和 python3 给出相同的结果。
一般来说,Python 语言标准在这里不作任何保证;事实上,正如定义的那样,字符串是不可变的,你正在做的事情 应该 无论如何都会咬你,因为你已经写了 Schlemiel the Painter's algorithm.
的形式
但在第一种情况下,作为实现细节,CPython(参考解释器)将帮助您解决问题,并在某些相当特定的条件下就地连接字符串(技术上违反了不变性保证)允许它遵守不变性规则的精神。最重要的条件是被连接的字符串必须只在一个地方被引用(如果不是,另一个引用将在原地改变,违反了 str
不可变的外观)。通过在每次串联后分配 str2 = str1
,您可以保证在串联时有 两个 引用,因此新的 str
必须 由每个连接组成,以保持字符串的明显不变性。这意味着更多的内存分配和释放,更多(并逐渐增加)内存副本等。
请注意,PEP 8, the Python style guide 中明确不鼓励依赖此优化:
Code should be written in a way that does not disadvantage other implementations of Python (PyPy, Jython, IronPython, Cython, Psyco, and such).
For example, do not rely on CPython's efficient implementation of in-place string concatenation for statements in the form a += b
or a = a + b
. This optimization is fragile even in CPython (it only works for some types) and isn't present at all in implementations that don't use refcounting. In performance sensitive parts of the library, the ''.join()
form should be used instead. This will ensure that concatenation occurs in linear time across various implementations.
关于 "only works for some types" 的说明很重要。此优化仅适用于str
;在 Python 2 中它不适用于 unicode
(即使 Python 3 的 str
是基于 Python 2 的 unicode
的实现) ,并且在 Python 3 中,它不适用于 bytes
(类似于 Python 2 的 str
)。
如果只是字符串的拼接,直接结束
test_str = "abcdefghijklmn123456789"
str1 = ""
str2 = ""
start = time.time()
for i in range(1, 100001):
str1 = str1 + test_str
str2 = str2 + test_str
if i % 20000 == 0:
print("time(sec) => {}".format(time.time() - start))
start = time.time()
恒定处理时间
time(sec) => 0.013324975967407227
time(sec) => 0.020363807678222656
time(sec) => 0.009979963302612305
time(sec) => 0.01744699478149414
time(sec) => 0.0227658748626709
令人费解的是,将连接的字符串分配给另一个变量会使过程越来越慢。
test_str = "abcdefghijklmn123456789"
str1 = ""
str2 = ""
start = time.time()
for i in range(1, 100001):
str1 = str1 + test_str
# str2 = str2 + test_str
# ↓
str2 = str1
if i % 20000 == 0:
print("time(sec) => {}".format(time.time() - start))
start = time.time()
处理时间会延迟。
time(sec) => 0.36466407775878906
time(sec) => 1.105351209640503
time(sec) => 2.6467738151550293
time(sec) => 5.891657829284668
time(sec) => 9.266698360443115
python2 和 python3 给出相同的结果。
一般来说,Python 语言标准在这里不作任何保证;事实上,正如定义的那样,字符串是不可变的,你正在做的事情 应该 无论如何都会咬你,因为你已经写了 Schlemiel the Painter's algorithm.
的形式但在第一种情况下,作为实现细节,CPython(参考解释器)将帮助您解决问题,并在某些相当特定的条件下就地连接字符串(技术上违反了不变性保证)允许它遵守不变性规则的精神。最重要的条件是被连接的字符串必须只在一个地方被引用(如果不是,另一个引用将在原地改变,违反了 str
不可变的外观)。通过在每次串联后分配 str2 = str1
,您可以保证在串联时有 两个 引用,因此新的 str
必须 由每个连接组成,以保持字符串的明显不变性。这意味着更多的内存分配和释放,更多(并逐渐增加)内存副本等。
请注意,PEP 8, the Python style guide 中明确不鼓励依赖此优化:
Code should be written in a way that does not disadvantage other implementations of Python (PyPy, Jython, IronPython, Cython, Psyco, and such).
For example, do not rely on CPython's efficient implementation of in-place string concatenation for statements in the form
a += b
ora = a + b
. This optimization is fragile even in CPython (it only works for some types) and isn't present at all in implementations that don't use refcounting. In performance sensitive parts of the library, the''.join()
form should be used instead. This will ensure that concatenation occurs in linear time across various implementations.
关于 "only works for some types" 的说明很重要。此优化仅适用于str
;在 Python 2 中它不适用于 unicode
(即使 Python 3 的 str
是基于 Python 2 的 unicode
的实现) ,并且在 Python 3 中,它不适用于 bytes
(类似于 Python 2 的 str
)。