Ajay
Cuál es mejor (o más rápido), un C++ for
bucle o el foreach
operador proporcionado por Qt? Por ejemplo, la siguiente condición
QList<QString> listofstrings;
¿Cual es mejor?
foreach(QString str, listofstrings)
{
//code
}
o
int count = listofstrings.count();
QString str = QString();
for(int i=0;i<count;i++)
{
str = listofstrings.at(i);
//Code
}
Realmente no importa en la mayoría de los casos.
La gran cantidad de preguntas en StackOverflow con respecto a si este método o ese método es más rápido desmiente el hecho de que, en la gran mayoría de los casos, el código pasa la mayor parte de su tiempo esperando a que los usuarios hagan algo.
Si usted son realmente preocupado, perfílelo usted mismo y actúe de acuerdo con lo que encuentre.
Pero creo que lo más probable es que encuentre que esta pregunta solo importa en el trabajo más intenso de procesamiento de datos. La diferencia bien puede ser solo un par de segundos e incluso entonces, solo cuando se procesa una gran cantidad de elementos.
Haz que tu código funcione primero. Entonces haz que funcione rápido (y solo si encuentra un problema de rendimiento real).
El tiempo dedicado a la optimización antes de que haya terminado la funcionalidad y pueda perfilar correctamente, es en su mayoría tiempo perdido.
-
El número pasó la etapa de broma hace mucho tiempo. Deberíamos escribir un bot de respuesta que busque “cuál es más rápido” y responda automáticamente: perfilarlo
– JaredPar
21 de abril de 2009 a las 4:28
-
Ver stackoverflow.com/questions/771092/… : veamos si sobrevive 🙂
– pax diablo
21 de abril de 2009 a las 4:57
-
No es que realmente se aplique tanto al ejemplo simple, pero lo que me gusta decir es: “El código incorrecto es lo menos optimizado posible”.
– Michael Burr
21 de abril de 2009 a las 5:27
-
@paxdiablo Estoy totalmente en desacuerdo. La respuesta que has dado es “Si estás realmente preocupado, perfilalo por ti mismo”. El hecho de que haya tenido suerte y el OP no haya hecho funcionar el código primero y haya realizado una optimización prematura no significa que sea una buena respuesta. Su respuesta habría sido realmente genial si realmente hubiera respondido la pregunta como lo han hecho varias personas a continuación y LUEGO agregó su comentario. Solo decir que lo pruebe usted mismo si realmente lo necesita no es una respuesta.
– scigor
3 de noviembre de 2016 a las 9:56
-
Trabajo en un mercado. Uno grande. Uno grande que vende millones de productos en un mes. Y cuando necesito generar un informe de eso para el gobierno, hace una gran diferencia. Usando el foreach de QT, el informe tardó 4 horas. Simplemente cambiarlo por fors normales cambió la velocidad a 15 min. Entonces, dependiendo de su aplicación, la diferencia es absurda.
– Dalton
19 de noviembre de 2016 a las 17:20
Parker Coates
En primer lugar, me gustaría decir que estoy de acuerdo con Pax y que la velocidad probablemente no entra en juego. foreach gana indiscutiblemente en base a la legibilidad, y eso es suficiente en el 98% de los casos.
Pero, por supuesto, los muchachos de Qt lo investigaron y de hecho hicieron algunos perfiles:
http://blog.qt.io/blog/2009/01/23/iterando-eficientemente/
La lección principal que se puede sacar de eso es: use referencias constantes en bucles de solo lectura, ya que evita la creación de instancias temporales. También hace que el propósito del bucle sea más explícito, independientemente del método de bucle que utilice.
Evan Terán
realmente no importa. Lo más probable es que si su programa es lento, este no es el problema. Sin embargo, debe tenerse en cuenta que no está haciendo una comparación completamente igual. Qt foreach
es más similar a esto (este ejemplo usará QList<QString>
):
for(QList<QString>::iterator it = Con.begin(); it != Con.end(); ++it) {
QString &str = *it;
// your code here
}
La macro puede hacer esto usando algunas extensiones del compilador (como GCC’s __typeof__
) para obtener el tipo de contenedor pasado. También imagina ese impulso BOOST_FOREACH
es muy similar en concepto.
La razón por la que su ejemplo no es justo es que su versión que no es Qt está agregando trabajo adicional.
Estás indexando en lugar de iterar realmente. Si está utilizando un tipo con asignación no contigua (sospecho que este podría ser el caso con QList<>
), entonces la indexación será más costosa ya que el código tiene que calcular “dónde” está el elemento n-ésimo.
Habiendo dicho eso. Eso todavía no importa La diferencia de tiempo entre esas dos piezas de código será insignificante, si es que existe. No pierdas tu tiempo preocupándote por eso. Escriba lo que le resulte más claro y comprensible.
EDITAR: Como beneficio adicional, actualmente estoy muy a favor de la versión C ++ 11 de la iteración de contenedores, es limpia, concisa y simple:
for(QString &s : Con) {
// you code here
}
-
Su declaración sobre
at()
contraoperator[]
el rendimiento no es correcto para Qt. Ambos realizan o no realizan comprobaciones de límites según las opciones de compilación. Las excepciones no se usan en Qt. Por el contrario, el la documentación dice “at()
puede ser más rápido queoperator[]()
porque nunca hace que se produzca una copia en profundidad”.– Tim Hoffman
23 de junio de 2016 a las 1:46
Ya que Qt 5.7 la foreach
macro está en desuso, Qt lo alienta a usar el C ++ 11 for
en cambio.
http://doc.qt.io/qt-5/qtglobal.html#foreach
(más detalles sobre la diferencia aquí: https://www.kdab.com/adiós-q_foreach/)
No quiero responder a la pregunta de cuál es más rápido, pero sí quiero decir cuál es mejor.
El mayor problema con el foreach de Qt es el hecho de que toma una copia de su contenedor antes de iterar sobre él. Podría decir ‘esto no importa porque las clases de Qt se cuentan’ pero debido a que se usa una copia, en realidad no cambia su contenedor original en absoluto.
En resumen, el foreach de Qt solo se puede usar para bucles de solo lectura y, por lo tanto, debe evitarse. Qt felizmente le permitirá escribir un bucle foreach que cree que actualizará/modificará su contenedor, pero al final todos los cambios se descartan.
-
Estoy de acuerdo. me encontré con un
foreach
mientras perfilaba: Resultó que había cambiado unQList
a unQVarLengthArray
(nuevamente después de perfilar) y encontró elforeach
copiando miQVarLengthArray
. Ups. Fui por un regularfor
loop y ese seguimiento de pila ya no aparecía en el generador de perfiles.– ben
20 de junio de 2014 a las 17:22
jalf
Primero, estoy completamente de acuerdo con la respuesta de que “no importa”. Elija la solución más limpia y optimícela si se convierte en un problema.
Pero otra forma de verlo es que, a menudo, la solución más rápida es la que describe su intención con mayor precisión. En este caso, el foreach de QT dice que le gustaría aplicar alguna acción para cada elemento en el contenedor.
Un simple bucle for dice que te gustaría un contador i
. Desea agregar repetidamente uno a este valor i, y siempre que sea menor que la cantidad de elementos en el contenedor, le gustaría realizar alguna acción.
En otras palabras, el bucle for normal sobreespecifica el problema. Agrega muchos requisitos que en realidad no son parte de lo que está tratando de hacer. tu no cuidado sobre el contador de bucles. Pero tan pronto como escribes un bucle for, tiene que estar allí.
Por otro lado, la gente de QT no ha hecho promesas adicionales que puedan afectar el rendimiento. Simplemente garantizan iterar a través del contenedor y aplicar una acción a cada uno.
En otras palabras, a menudo la solución más limpia y elegante es también la más rápida.
-
Estoy de acuerdo. me encontré con un
foreach
mientras perfilaba: Resultó que había cambiado unQList
a unQVarLengthArray
(nuevamente después de perfilar) y encontró elforeach
copiando miQVarLengthArray
. Ups. Fui por un regularfor
loop y ese seguimiento de pila ya no aparecía en el generador de perfiles.– ben
20 de junio de 2014 a las 17:22
justinhj
El foreach de Qt tiene una sintaxis más clara para el bucle for en mi humilde opinión, por lo que es mejor en ese sentido. En cuanto al rendimiento, dudo que haya algo en él.
Podrías considerar usar el BOOST_FOREACH en cambio, ya que es un bucle for elegante bien pensado, y es portátil (y presumiblemente llegará a C ++ algún día y también es una prueba para el futuro).
Solo una nota rápida de que si no planea modificar la variable de bucle foreach, debe usar una const QString& en su lugar, que también tiene implicaciones en la velocidad.
– swongu
21 de abril de 2009 a las 17:24
Aquí hay una explicación de por qué desea tener cuidado de incluir la const: labs.qt.nokia.com/2009/01/23/iteración-eficiente
–Jeff Allen
12 de julio de 2011 a las 15:01
La adición importante a esta pregunta es que nunca debes usar Qt
foreach
para contenedores que no sean Qt, lo más probable es que se realice una copia profunda y esto es lo que no desea incluso sin perfilarlo de antemano.– Predelnik
16 de abril de 2015 a las 7:29
Desde Qt 5.7 el
foreach
macro está en desuso, vea mi respuesta a continuación para obtener más detalles.– ymoreau
24 oct 2019 a las 17:41