library Performance de jointure de chaîne python



python join string (5)

Il y a beaucoup d'articles sur le web concernant les performances de python, la première chose que vous lisez: concaténer les chaînes ne devrait pas être fait en utilisant '+': éviter s1 + s2 + s3, à la place utiliser str.join

J'ai essayé ce qui suit: concaténation de deux chaînes dans le cadre d'un chemin de répertoire: trois approches:

  1. '+' que je ne devrais pas faire
  2. str.join
  3. os.path.join

Voici mon code:

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

Voici les résultats (python 2.5 WinXP)

0.0182201927899
0.0262544541275
0.120238186697

Ne devrait-il pas être exactement l'inverse?


Answer #1

Il est vrai que vous ne devriez pas utiliser '+'. Votre exemple est assez spécial, essayez le même code avec:

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

Ensuite, la deuxième version (str.join) est beaucoup plus rapide.


Answer #2

La plupart des problèmes de performance liés à la concaténation de chaînes sont des problèmes de performance asymptotique. Les différences deviennent donc plus importantes lorsque vous concaténéz de nombreuses chaînes longues. Dans votre exemple, vous effectuez la même concaténation plusieurs fois. Vous ne créez pas de longue chaîne, et il se peut que l'interpréteur python optimise vos boucles. Cela expliquerait pourquoi le temps augmente lorsque vous passez à str.join et path.join - ce sont des fonctions plus complexes qui ne sont pas aussi facilement réduites. (os.path.join fait beaucoup de vérifications sur les chaînes pour voir si elles ont besoin d'être réécrites avant qu'elles ne soient concaténées, ce qui sacrifie certaines performances pour des raisons de portabilité.)

D'ailleurs, comme les chemins de fichiers ne sont généralement pas très longs, vous voudrez probablement utiliser os.path.join pour la portabilité. Si la performance de la concaténation est un problème, vous faites quelque chose de très bizarre avec votre système de fichiers.


Answer #3

Le conseil concerne la concaténation de beaucoup de chaînes.

Pour calculer s = s1 + s2 + ... + sn,

1) en utilisant +. Une nouvelle chaîne s1 + s2 est créée, puis une nouvelle chaîne s1 + s2 + s3 est créée, ..., etc., donc beaucoup d'allocation de mémoire et d'opérations de copie sont impliquées. En effet, s1 est copié n-1 fois, s2 est copié n-2 fois, ..., etc.

2) en utilisant "" .join ([s1, s2, ..., sn]). La concaténation est effectuée en une passe et chaque caractère des chaînes est copié une seule fois.

Dans votre code, join est appelée à chaque itération, c'est comme si vous utilisiez +. La méthode correcte consiste à collecter les éléments dans un tableau, puis à appeler la jointure.

edit: correction de la faute de frappe


Answer #4

Je voudrais ajouter un lien vers le wiki python, où il y a des notes sur la concaténation des chaînes et aussi que " cette section est un peu fausse avec python2.5." La concaténation en chaîne Python 2.5 est assez rapide ".

Je crois que la concaténation de chaînes a eu une grande amélioration depuis 2.5, et que même si str.join est encore plus rapide (spécialement pour les grandes chaînes), vous ne verrez pas autant d'améliorations que dans les anciennes versions de Python.

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


Answer #5

La concaténation de chaînes ( + ) a une implémentation optimisée sur CPython. Mais cela peut ne pas être le cas sur d'autres architectures comme Jython ou IronPython. Donc, quand vous voulez que votre code fonctionne correctement sur ces interpréteurs, vous devez utiliser la méthode .join() sur les chaînes. os.path.join() est spécifiquement destiné à rejoindre les chemins du système de fichiers. Il prend également en charge différents séparateurs de chemins. Ce serait la bonne façon de construire un nom de fichier.





string