otra - ¿Es.NET 4.0 Runtime más lento que.NET 2.0 Runtime?
net framework 4.5 full (4)
Después de actualizar mis proyectos a .NET 4.0 (con VS2010) me di cuenta de que se ejecutan más lentamente de lo que eran en .NET 2.0 (VS2008). Así que decidí comparar una aplicación de consola simple tanto en VS2008 como en VS2010 con varios marcos de trabajo de destino:
using System;
using System.Diagnostics;
using System.Reflection;
namespace RuntimePerfTest
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine(Assembly.GetCallingAssembly().ImageRuntimeVersion);
Stopwatch sw = new Stopwatch();
while (true)
{
sw.Reset();
sw.Start();
for (int i = 0; i < 1000000000; i++)
{
}
TimeSpan elapsed = sw.Elapsed;
Console.WriteLine(elapsed);
}
}
}
}
Aquí están los resultados:
- VS2008
- Marco de destino 2.0: ~ 0.25 segundos
- Marco de destino 3.0: ~ 0.25 segundos
- Marco de destino 3.5: ~ 0.25 segundos
- VS2010
- Marco de destino 2.0: ~ 3.8 segundos
- Marco de destino 3.0: ~ 3.8 segundos
- Marco de destino 3.5: ~ 1.51 segundos
- Perfil del cliente de Target Framework 3.5: ~ 3.8 segundos
- Marco de destino 4.0: ~ 1.01 segundos
- Perfil de cliente de Target Framework 4.0: ~ 1.01 segundos
Mi conclusión inicial es, obviamente, que los programas compilados con VS2008 funcionan más rápido que los programas compilados con VS2010.
¿Alguien puede explicar esos cambios de rendimiento entre VS2008 y VS2010? y entre diferentes marcos de destino dentro de VS2010?
Creo que lo tengo.
Si está ejecutando en una máquina de 64 bits, asegúrese de que la compilación esté configurada en "Cualquier CPU" en lugar de "x86". Al hacerlo solucioné el problema en mi máquina.
El valor predeterminado para nuevos proyectos cambió en VS2010 de "Cualquier CPU" a "x86". Creo que esto fue para que Editar y Continuar funcionen por defecto en máquinas de 64 bits (ya que solo es compatible con x86).
Ejecutar un proceso x86 en una máquina de 64 bits es obviamente algo subóptimo.
EDITAR: De acuerdo con los comentarios de Dustin, ejecutar x86 en lugar de x64 puede tener ventajas de rendimiento en términos de un uso más eficiente de la memoria (referencias más cortas).
También me comuniqué con Dustin sobre esto por correo electrónico, e incluyó estas razones:
FWIW, la plataforma de destino predeterminada no se modificó para admitir ENC. Ya habíamos enviado ENC roto en x64 para 2 lanzamientos. Así que, por sí mismo, ENC no era realmente una razón convincente para cambiar. Las razones principales por las que cambiamos (en ningún orden en particular) fueron:
IntelliTrace no es compatible con x64. Por lo tanto, una de las características nuevas más interesantes no funcionará en x64 Windows para cualquier proyecto de CPU.
Los EXE x64 se ejecutan más lentamente en Windows x64 que los EXEs x86. Por lo tanto, la idea de la depuración x86, la versión x64 significaría que las compilaciones "optimizadas" en la versión realmente se desempeñarán peor.
Los clientes se quejan cuando implementan una aplicación y descubren que no funciona, aunque funcionó en su máquina. Estos a menudo estaban alrededor de P / Invoke, pero hay muchas otras suposiciones que se pueden hacer en una aplicación que se puede romper cuando se ejecuta con un bitness diferente.
Las razones anteriores, junto con el hecho de que una CPU Cualquiera no ofrece beneficios (es decir, no puede aprovechar el espacio de direcciones expandido porque el EXE aún puede ejecutarse en x86) fue la razón por la que se cambió el valor predeterminado.
Rick Byers tiene una excelente publicación sobre este tema here .
Creo que su punto de referencia es defectuoso. El código IL de VS 2008 y VS 2010 para su programa de muestra es idéntico en el modo de lanzamiento (VS 2008 tiene como objetivo .NET 2.0 y VS 2010 para .NET 4.0 con la configuración predeterminada). Por lo tanto, no debería ver una diferencia en los tiempos entre VS 2008 y VS 2010. Ambos compiladores emiten el siguiente código:
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 69 (0x45)
.maxstack 2
.locals init ([0] class [System]System.Diagnostics.Stopwatch sw,
[1] int32 i,
[2] valuetype [mscorlib]System.TimeSpan elapsed)
IL_0000: call class [mscorlib]System.Reflection.Assembly [mscorlib]System.Reflection.Assembly::GetCallingAssembly()
IL_0005: callvirt instance string [mscorlib]System.Reflection.Assembly::get_ImageRuntimeVersion()
IL_000a: call void [mscorlib]System.Console::WriteLine(string)
IL_000f: newobj instance void [System]System.Diagnostics.Stopwatch::.ctor()
IL_0014: stloc.0
IL_0015: ldloc.0
IL_0016: callvirt instance void [System]System.Diagnostics.Stopwatch::Reset()
IL_001b: ldloc.0
IL_001c: callvirt instance void [System]System.Diagnostics.Stopwatch::Start()
IL_0021: ldc.i4.0
IL_0022: stloc.1
IL_0023: br.s IL_0029
IL_0025: ldloc.1
IL_0026: ldc.i4.1
IL_0027: add
IL_0028: stloc.1
IL_0029: ldloc.1
IL_002a: ldc.i4 0x3b9aca00
IL_002f: blt.s IL_0025
IL_0031: ldloc.0
IL_0032: callvirt instance valuetype [mscorlib]System.TimeSpan [System]System.Diagnostics.Stopwatch::get_Elapsed()
IL_0037: stloc.2
IL_0038: ldloc.2
IL_0039: box [mscorlib]System.TimeSpan
IL_003e: call void [mscorlib]System.Console::WriteLine(object)
IL_0043: br.s IL_0015
} // end of method Program::Main
Una cosa que podría ser diferente es el objetivo de la plataforma. VS 2010 usa x86
como el destino predeterminado de la plataforma, mientras que VS 2008 usa AnyCPU
. Si está en un sistema de 64 bits, esto resultará en el uso de diferentes compiladores JIT para las compilaciones de VS 2008 vs. VS 2010. Esto podría llevar a resultados diferentes, ya que los compiladores JIT se desarrollan por separado.
Estoy de acuerdo en que el punto de referencia es un defecto.
- Es demasiado corto
- Como se señaló anteriormente, es probable que los diferentes JIT para x86 / x64 optimicen el bucle de manera diferente.
- Realmente solo prueba las variables de pila que probablemente están JITted para un rápido acceso de registro. Un punto de referencia del mundo más real debería al menos mover el acceso al espacio de direcciones.
La mayoría del tiempo adicional es probablemente tomado por la capa WoW en los casos x86. Sin embargo, las ineficiencias inherentes de un proceso x64 probablemente superarán la sobrecarga de la capa de WoW en un punto de referencia más largo que realmente toca la memoria. De hecho, si el punto de referencia fuera a acceder a la memoria (creando y accediendo a objetos en el montón), vería los beneficios de optimización de puntero de capas de WoW.
Tenemos el mismo problema. Después de convertir el proyecto wpf de .NET 3.5 (VS2008) a .NET 4 (VS2010), la GUI es mucho menos receptiva (casi 1 segundo de retraso por cada clic).
Después de algunas investigaciones, pensamos que es porque Visual Studio 2010 consume muchos más recursos y todo es más lento cuando degustamos desde VS2010. Cuando ejecutamos el proyecto creado como .exe, se ejecuta de nuevo rápido.