c# - significa - operador decremento c
¿Hay alguna diferencia de rendimiento entre++ i e i++ en C#? (9)
¿Hay alguna diferencia de rendimiento entre el uso de algo así como
for(int i = 0; i < 10; i++) { ... }
y
for(int i = 0; i < 10; ++i) { ... }
¿o es capaz el compilador de optimizar de tal manera que sean igualmente rápidos en el caso en que sean funcionalmente equivalentes?
Editar: Esto fue preguntado porque tuve una discusión con un compañero de trabajo al respecto, no porque creo que sea una optimización útil en ningún sentido práctico. Es en gran parte académica.
Chicos, chicos, las "respuestas" son para C y C ++.
C # es un animal diferente.
Use ILDASM para ver el resultado compilado para verificar si hay una diferencia MSIL.
¿Tiene en mente una pieza concreta de código y liberación de CLR? Si es así, cotejarlo. Si no, olvídate de eso. Micro-optimización, y todo eso ... Además, ni siquiera puedes estar seguro de que una versión CLR diferente produzca el mismo resultado.
Ah ... Abre de nuevo. DE ACUERDO. Aquí está el trato.
ILDASM es un comienzo, pero no un final. La clave es: ¿qué generará el JIT para el código de ensamblaje?
Esto es lo que quieres hacer.
Tome un par de muestras de lo que está tratando de ver. Obviamente puedes cronometrarlos si quieres, pero supongo que quieres saber más que eso.
Esto es lo que no es obvio. El compilador de C # genera algunas secuencias de MSIL que no son óptimas en muchas situaciones. El JIT se ajustó para tratar con estos y peculiaridades de otros idiomas. El problema: solo se han ajustado los ''caprichos'' que alguien ha notado.
Realmente quiere hacer una muestra que tenga sus implementaciones para probar, regresa a main (o donde sea), Sleep () s, o algo donde pueda adjuntar un depurador, luego vuelva a ejecutar las rutinas.
NO QUIERES iniciar el código bajo el depurador o el JIT generará un código no optimizado, y parece que quieres saber cómo se comportará en un entorno real. El JIT hace esto para maximizar la información de depuración y minimizar la ubicación actual de la fuente de ''saltar alrededor''. Nunca inicie una evaluación de perf bajo el depurador.
DE ACUERDO. Entonces, una vez que el código se ha ejecutado una vez (es decir: el JIT ha generado un código para él), luego conecte el depurador durante la suspensión (o lo que sea). Luego observe el x86 / x64 que se generó para las dos rutinas.
Mi instinto me dice que si está utilizando ++ i / i ++ como describió, es decir: en una expresión independiente donde el resultado del valor r no se vuelve a utilizar, no habrá ninguna diferencia. ¡Pero no será divertido ir a buscar y ver todas las cosas buenas! :)
No hay diferencia en el código intermedio generado para ++ i y i ++ en este caso. Dado este programa:
class Program
{
const int counter = 1024 * 1024;
static void Main(string[] args)
{
for (int i = 0; i < counter; ++i)
{
Console.WriteLine(i);
}
for (int i = 0; i < counter; i++)
{
Console.WriteLine(i);
}
}
}
El código IL generado es el mismo para ambos bucles:
IL_0000: ldc.i4.0
IL_0001: stloc.0
// Start of first loop
IL_0002: ldc.i4.0
IL_0003: stloc.0
IL_0004: br.s IL_0010
IL_0006: ldloc.0
IL_0007: call void [mscorlib]System.Console::WriteLine(int32)
IL_000c: ldloc.0
IL_000d: ldc.i4.1
IL_000e: add
IL_000f: stloc.0
IL_0010: ldloc.0
IL_0011: ldc.i4 0x100000
IL_0016: blt.s IL_0006
// Start of second loop
IL_0018: ldc.i4.0
IL_0019: stloc.0
IL_001a: br.s IL_0026
IL_001c: ldloc.0
IL_001d: call void [mscorlib]System.Console::WriteLine(int32)
IL_0022: ldloc.0
IL_0023: ldc.i4.1
IL_0024: add
IL_0025: stloc.0
IL_0026: ldloc.0
IL_0027: ldc.i4 0x100000
IL_002c: blt.s IL_001c
IL_002e: ret
Dicho esto, es posible (aunque muy poco probable) que el compilador JIT pueda realizar algunas optimizaciones en ciertos contextos que favorecerán una versión sobre la otra. Sin embargo, si existe tal optimización, probablemente solo afectaría la iteración final (o tal vez la primera) de un ciclo.
En resumen, no habrá diferencia en el tiempo de ejecución del simple preincremento o incremento posterior de la variable de control en la construcción de bucle que ha descrito.
static void Main(string[] args) {
var sw = new Stopwatch(); sw.Start();
for (int i = 0; i < 2000000000; ++i) { }
//int i = 0;
//while (i < 2000000000){++i;}
Console.WriteLine(sw.ElapsedMilliseconds);
Promedio de 3 carreras:
para con i ++: 1307 para con ++ i: 1314
mientras que con i ++: 1261 mientras que con ++ i: 1276
Eso es un Celeron D a 2,53 Ghz. Cada iteración tomó alrededor de 1,6 ciclos de CPU. Eso significa que la CPU estaba ejecutando más de 1 instrucción en cada ciclo o que el compilador JIT desenrolló los bucles. La diferencia entre i ++ y ++ i fue de solo 0,01 ciclos de CPU por iteración, probablemente debido a los servicios del sistema operativo en segundo plano.
Además de otras respuestas, puede haber una diferencia si tu i
no es un int
. En C ++ , si es un objeto de una clase que tiene los operadores ++()
y ++(int)
sobrecargados, entonces puede hacer una diferencia, y posiblemente un efecto secundario. El rendimiento de ++i
debería ser mejor en este caso (depende de la implementación).
Si estás haciendo esta pregunta, estás tratando de resolver el problema equivocado.
La primera pregunta es "¿cómo puedo mejorar la satisfacción del cliente con mi software haciendo que funcione más rápido?" y la respuesta casi nunca es "use ++ i en lugar de i ++" o viceversa.
De la publicación de Coding Horror "El hardware es barato, los programadores son caros ":
Reglas de optimización:
Regla 1: No lo hagas
Regla 2 (solo para expertos): No lo hagas todavía.
- MA Jackson
Leí la regla 2 en el sentido de "primero escriba un código limpio y claro que satisfaga las necesidades de su cliente, y luego agilice el proceso donde sea demasiado lento". Es muy poco probable que ++i
vs. i++
sea la solución.
Como ha demostrado Jim Mischel, el compilador generará MSIL idéntico para las dos formas de escribir el for-loop.
Pero eso es todo: no hay ninguna razón para especular sobre el JIT o realizar mediciones de velocidad. Si las dos líneas de código generan MSIL idénticos, no solo se comportarán de manera idéntica, sino que son efectivamente idénticos.
Ningún posible JIT sería capaz de distinguir entre los bucles, por lo que el código máquina generado necesariamente debe ser idéntico también.
De acuerdo con esta respuesta , i ++ usa una instrucción de CPU más que ++ i. Pero si esto resulta en una diferencia en el rendimiento, no lo sé.
Como cualquiera de los bucles se puede reescribir fácilmente para usar un incremento posterior o un preincremento, supongo que el compilador siempre usará la versión más eficiente.