otros ya han proporcionado un excelente commen tary, incluido el análisis del código ensamblador generado. Recomiendo encarecidamente que los lea cuidadosamente. Como han señalado, este tipo de preguntas no pueden ser respondidas sin una cierta cuantificación, así que vamos a jugar un poco.
Primero, vamos a necesitar un programa. Nuestro plan es este: generaremos cadenas cuyas longitudes sean potencias de dos, y probaremos todas las funciones sucesivamente. Lo ejecutamos una vez para preparar el caché y luego, por separado, cronometrar 4096 iteraciones usando la resolución más alta disponible para nosotros. Una vez que hayamos terminado, calcularemos algunas estadísticas básicas: mínimo, máximo y el promedio de movimiento simple y lo volcaremos. Entonces podemos hacer un análisis rudimentario.
Además de los dos algoritmos que ya has mostrado, mostraré una tercera opción que no implica el uso de un contador en absoluto, confiando en cambio en una resta, y mezclaré cosas lanzando en std::strlen
, solo para ver qué pasa. Será un lanzamiento interesante.
A través de la magia de la televisión de nuestro pequeño programa que ya está escrito, por lo que compilarlo con gcc -std=c++11 -O3 speed.c
y obtenemos el arranque producir algunos datos. He hecho dos gráficos separados, uno para cadenas cuyo tamaño es de 32 a 8192 bytes y otro para cadenas cuyo tamaño es desde 16384 hasta 1048576 bytes de longitud. En los siguientes gráficos, el eje Y es el tiempo consumido en nanosegundos y el eje X muestra la longitud de la cadena en bytes.
Sin más preámbulos, vamos a ver el rendimiento para las "pequeñas" cuerdas de 32 a 8192 bytes:
ahora este es interesante. No solo la función std::strlen
supera a todo en todos los ámbitos, sino que también lo hace con entusiasmo, ya que su rendimiento es mucho más estable.
¿Cambiará la situación si nos fijamos en las cadenas más grandes, desde 16.384 hasta llegar a 1.048.576 bytes de longitud?
o menos. La diferencia es cada vez más pronunciada. Como nuestras funciones escritas a medida huff-and-puff, std::strlen
continúa funcionando admirablemente.
Una observación interesante es que no se puede traducir necesariamente el número de instrucciones de C++ (o incluso el número de instrucciones de ensamblaje) al rendimiento, ya que las funciones cuyos cuerpos contienen menos instrucciones a veces tardan más en ejecutarse.
Una observación aún más interesante - y importante es darse cuenta de lo bien que funciona la función str::strlen
.
Entonces, ¿qué significa todo esto nos llegar?
Primera conclusión: No reinventar la rueda. Use las funciones estándar disponibles para usted. No solo están ya escritos, sino que están muy optimizados y seguramente superará a todo lo que pueda escribir a menos que sea Agner Fog.
Segunda conclusión: a menos que tenga datos duros de un generador de perfiles que una sección particular de código o función es punto caliente en su aplicación, no se moleste en optimizar el código. Los programadores son notoriamente malos a la hora de detectar puntos críticos observando la función de alto nivel.
Tercera conclusión: prefieren optimizaciones algorítmicas con el fin de mejorar el rendimiento del código. Pon tu mente a trabajar y deja que el compilador baraje los bits.
Su pregunta original era: "¿por qué la función slen2
es más lenta que slen1
?" Podría decir que no es fácil responder sin mucha más información, y aun así podría ser mucho más larga y más complicada de lo que usted desea. En cambio, lo que voy a decir es lo siguiente:
quién le importa por qué?¿Por qué te molestas con esto? Utilice std::strlen
- que es mejor que cualquier cosa que pueda armar - y pase a resolver problemas más importantes - porque estoy seguro de que este no es el mayor problema en su aplicación.
¿Por qué utilizar un doble en lugar de un largo sin signo? Además, debe intentar compilar sin optimización y ver los resultados. Ah, y deberías ejecutar ambas unas veinte veces y calcular las duraciones promedio. –
¿Error de predicción de rama? Copias de datos innecesarias? Intente mirar el ensamblaje generado. Además, intente activar la optimización, puede solucionar el problema. – dmckee
¿Qué tipo de compilador está utilizando para esto? Lo ejecuto con mi gcc 4.4.5 y tardan casi el mismo tiempo, alrededor de 2s. Con i configurado en 110021100, ambos usan alrededor de 19 segundos. –