производительность соединения строки Python - PullRequest
12 голосов
/ 25 января 2009

В Интернете много статей о производительности Python, первое, что вы прочитали: конкатенация строк не должна выполняться с помощью '+': избегайте s1 + s2 + s3, вместо этого используйте str.join

Я попробовал следующее: объединить две строки как часть пути к каталогу: три подхода:

  1. '+', чего я не должен делать
  2. str.join
  3. os.path.join

Вот мой код:

import os,time

s1='/part/one/of/dir'
s2='part/two/of/dir'
N=10000

t=time.clock()
for i in xrange(N):
    s=s1+os.sep+s2
print time.clock()-t

t=time.clock()
for i in xrange(N):
    s=os.sep.join((s1,s2))
print time.clock()-t

t=time.clock()
for i in xrange(N):
    s=os.path.join(s1,s2)
print time.clock()-t

Вот результаты (Python 2.5 WinXP)

0.0182201927899
0.0262544541275
0.120238186697

Разве не должно быть наоборот?

Ответы [ 6 ]

12 голосов
/ 25 января 2009

Большинство проблем с производительностью при конкатенации строк - это асимптотическая производительность, поэтому различия становятся наиболее значительными, когда вы объединяете много длинных строк. В вашем примере вы выполняете одну и ту же конкатенацию много раз. Вы не создаете длинную строку, и, возможно, интерпретатор Python оптимизирует ваши циклы. Это объясняет, почему время увеличивается при переходе к str.join и path.join - это более сложные функции, которые не так легко сократить. (os.path.join много проверяет строки, чтобы выяснить, нужно ли их каким-либо образом переписать перед их объединением. Это жертвует некоторой производительностью ради переносимости.)

Кстати, поскольку пути к файлам обычно не очень длинные, вы почти наверняка захотите использовать os.path.join ради переносимости. Если производительность конкатенации является проблемой, вы делаете что-то очень странное с вашей файловой системой.

5 голосов
/ 25 января 2009

Разве не должно быть наоборот?

Не обязательно. Я недостаточно хорошо знаком с внутренностями Python, чтобы комментировать конкретно, но некоторые общие наблюдения заключаются в том, что ваш первый цикл использует простой оператор +, который, вероятно, реализован как примитив во время выполнения. Напротив, другие циклы сначала должны разрешить имя модуля, найти найденную там переменную / класс, а затем вызвать функцию-член для этого.

Еще одно замечание: ваш цикл может быть слишком маленьким, чтобы давать значимые числа. Учитывая ваше низкое общее время выполнения, это, вероятно, делает ваши тесты бесполезными.

Кроме того, ваш тестовый пример сильно специализирован на двух коротких строках. Такие случаи никогда не дают четкого представления об эффективности пограничных случаев.

4 голосов
/ 25 января 2009

Совет касается объединения множества строк.

Для вычисления s = s1 + s2 + ... + sn,

1) с помощью +. Создается новая строка s1 + s2, затем создается новая строка s1 + s2 + s3, ... и т. Д., Поэтому требуется много операций по выделению памяти и копированию. Фактически, s1 копируется n-1 раз, s2 копируется n-2 раза, ... и т. Д.

2) используя "" .join ([s1, s2, ..., sn]). Конкатенация выполняется за один проход, и каждый символ в строках копируется только один раз.

В вашем коде join вызывается на каждой итерации, так что это похоже на использование +. Правильный способ - собрать элементы в массив, а затем вызвать для него соединение.

edit: исправлена ​​опечатка

4 голосов
/ 25 января 2009

Это правда, что вы не должны использовать «+». Ваш пример совершенно особенный, попробуйте тот же код с:

s1='*'*100000
s2='+'*100000

Тогда вторая версия (str.join) будет намного быстрее.

1 голос
/ 11 мая 2009

Я хотел бы добавить ссылку на вики Python, где есть примечания относительно конкатенации строк, а также, что " этот раздел несколько неправильный с python2.5. Конкатенация строк Python 2.5 довольно быстрая " .

Я считаю, что конкатенация строк значительно улучшилась с 2.5, и, хотя str.join все еще быстрее (особенно для больших строк), вы не увидите такого большого улучшения, как в более старых версиях Python.

http://wiki.python.org/moin/PythonSpeed/PerformanceTips#StringConcatenation

1 голос
/ 25 января 2009

Конкатенация строк (+) имеет оптимизированную реализацию на CPython. Но это может не относиться к другим архитектурам, таким как Jython или IronPython. Поэтому, если вы хотите, чтобы ваш код хорошо работал на этих интерпретаторах, вы должны использовать метод .join() для строк. os.path.join() специально предназначен для объединения путей файловой системы. Он также заботится о различных разделителях пути. Это был бы правильный способ создать имя файла.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...