2009-01-24 17 views
10

Hay un montón de artículos en la web referentes al desempeño pitón, lo primero que se lee: concatenación de cadenas no debe hacerse uso de '+': evitar S1 + S2 + S3, en lugar de utilizar str.joincadena de Python rendimiento de unión

he intentado lo siguiente: la concatenación de dos cadenas como parte de una ruta de directorio: tres enfoques:

  1. '+', que no debo hacer
  2. str.join
  3. os.path.join

Aquí está mi código:

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 

Aquí los resultados (Python 2.5 WinXP)

0.0182201927899 
0.0262544541275 
0.120238186697 

¿No debería ser exactamente al revés?

+1

Si yo te recomiendo cambiar el nombre del título de tu pregunta a la "cadena de Python rendimiento de unión", simplemente por lo que es más evidente a las personas que podrían presentar una pregunta duplicado. –

+1

También, un poco fuera de tema, pero es posible que desee ver el módulo 'timeit' para hacer los tiempos. –

+0

cambió el título – Danny

Respuesta

4

Es cierto que no debe usar '+'. Su ejemplo es bastante especial, pruebe el mismo código con:

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

Luego, la segunda versión (str.join) es mucho más rápida.

12

La mayoría de los problemas de rendimiento con la concatenación de cadenas son de rendimiento asintótico, por lo que las diferencias se vuelven más significativas cuando se concatenan muchas cadenas largas. En su muestra, está realizando la misma concatenación muchas veces. No estás creando cadenas largas, y es posible que el intérprete de Python esté optimizando tus bucles. Esto explicaría por qué el tiempo aumenta cuando te mueves a str.join y path.join: son funciones más complejas que no se reducen tan fácilmente. (os.path.join realiza una gran cantidad de comprobaciones en las cadenas para ver si necesitan ser reescritas de alguna manera antes de que se concatenan. Esto sacrifica algún rendimiento por el bien de la portabilidad.)

Por cierto, ya que las rutas de archivos no suelen ser muy largas, casi seguro que desea utilizar os.path.join por el bien de la portabilidad. Si el rendimiento de la concatenación es un problema, estás haciendo algo muy extraño con tu sistema de archivos.

5

¿No debería ser exactamente al revés?

No necesariamente

. No conozco los aspectos internos de Python lo suficientemente bien como para comentar específicamente, pero algunas observaciones comunes son que su primer ciclo usa un operador simple + que es implementado de manera proverbial por el tiempo de ejecución. Por el contrario, los otros bucles primero tienen que resolver un nombre de módulo, resolver la variable/clase que se encuentra allí y luego llamar a una función miembro sobre eso.

Otra nota es que su bucle podría ser demasiado pequeño para producir números significativos. Teniendo en cuenta su bajo tiempo de ejecución general, esto probablemente haga que sus pruebas sean inútiles.

Además, su caso de prueba está altamente especializado en dos cadenas cortas. Tales casos nunca dan una imagen clara del rendimiento de la caja de borde.

4

El consejo es sobre la concatenación de muchas cadenas.

Para calcular s = s1 + s2 + ...+ sn,

1) usando +. Se crea una nueva cadena s1 + s2, luego se crea una nueva cadena s1 + s2 + s3, ..., etc., lo que implica una gran cantidad de operaciones de asignación y copia de memoria. De hecho, s1 se copia n-1 veces, s2 se copia tiempo n-2, ..., etc.

2) usando "" .join ([s1, s2, ..., sn]). La concatenación se realiza en una pasada, y cada carácter en las cadenas se copia una sola vez.

En su código, se llama a join en cada iteración, por lo que es como usar +. La forma correcta es recoger los elementos en una matriz, luego llamar a unirse a ella.

edición: arreglado el error tipográfico

+0

tiene un error ... no es "joing" sino "join" –

1

La concatenación de cadenas (+) tiene una implementación optimizada de CPython. Pero este puede no ser el caso en otras arquitecturas como Jython o IronPython. Entonces, cuando desee que su código tenga un buen rendimiento en estos intérpretes, debe usar el método .join() en cadenas. os.path.join() está específicamente diseñado para unir rutas de sistema de archivos. También se ocupa de los diferentes separadores de ruta. Esta sería la forma correcta de construir un nombre de archivo.

0

Me gustaría agregar un enlace a la wiki de python, donde hay notas sobre la concatenación de cadenas y también que "esta sección es algo incorrecta con python2.5. La concatenación de cadenas de Python 2.5 es bastante rápida".

creo que la concatenación de cadenas tenía una gran mejora desde 2,5, y que aunque str.join es aún más rápido (especialmente para las grandes cadenas), no se ve tanta mejora como en las versiones anteriores de Python.

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