.NET 4.0 Runtime медленнее, чем .NET 2.0 Runtime? - PullRequest
22 голосов
/ 19 мая 2010

После того, как я обновил свои проекты до .NET 4.0 (с VS2010), я понял, что они работают медленнее, чем в .NET 2.0 (VS2008). Поэтому я решил сравнить простое консольное приложение в VS2008 и VS2010 с различными Target Frameworks:

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);
            }
        }
    }
}

Вот результаты:

  • VS2008
    • Target Framework 2.0: ~ 0,25 секунды
    • Target Framework 3.0: ~ 0,25 секунды
    • Target Framework 3.5: ~ 0,25 секунды
  • VS2010
    • Target Framework 2.0: ~ 3,8 секунды
    • Target Framework 3.0: ~ 3,8 секунды
    • Target Framework 3.5: ~ 1,51 секунды
    • Профиль клиента Target Framework 3.5: ~ 3,8 секунды
    • Target Framework 4.0: ~ 1,01 секунды
    • Профиль клиента Target Framework 4.0: ~ 1,01 секунды

Мой первоначальный вывод состоит в том, что программы, скомпилированные с VS2008, работают быстрее, чем программы, скомпилированные с VS2010.

Может кто-нибудь объяснить эти изменения производительности между VS2008 и VS2010? а между разными Target Frameworks внутри самого VS2010?

Ответы [ 4 ]

27 голосов
/ 19 мая 2010

Я думаю, что у меня есть.

Если вы работаете на 64-битной машине, убедитесь, что для сборки задано «Любой процессор», а не «x86». Это решило проблему на моей машине.

Значение по умолчанию для новых проектов изменено в VS2010 с «Любой ЦП» на «x86» - я полагаю, это должно было заставить Edit и Continue работать по умолчанию на 64-битных машинах (поскольку он поддерживает только x86).

Запуск процесса x86 на 64-битной машине, очевидно, несколько неоптимален.

РЕДАКТИРОВАТЬ: Согласно комментариям Дастина, запуск x86 вместо x64 может иметь преимущества в плане производительности при более эффективном использовании памяти (более короткие ссылки).

Я также переписывался с Дастином по электронной почте, и он привел следующие причины:

FWIW, целевая платформа по умолчанию не был изменен для поддержки ENC. Мы имеем уже поставленный ENC сломан на x64 для 2 релиза. Сам по себе ENC не был действительно веская причина для переключения. Основные причины, по которым мы перешли конкретный заказ) были:

  • IntelliTrace не поддерживается в x64. Итак, один из самых крутых новых функции не будут работать на 64-разрядной Windows для Любые проекты CPU.

  • x64 EXE работают медленнее в x64 Windows, чем x86 EXE. Итак, идея х86 отладка, выпуск x64 будет означать, что «Оптимизированные» сборки в Release на самом деле выступают хуже.

  • Жалобы клиентов при развертывании приложения и обнаружении, что оно не работает, хотя работал их машина. Они часто были вокруг P / Invoke, но там много чего другого предположения, которые могут быть сделаны в приложение, которое может сломаться при запуске с разной битностью.

Приведенные выше причины в сочетании с Дело в том, что любой процессор не приносит никаких льготы (т.е. вы не можете взять преимущество расширенного адреса пространство, потому что EXE все еще может работать на x86) было причиной того, что по умолчанию был переключен.

Рик Байерс имеет отличный пост на эту тему здесь .

8 голосов
/ 19 мая 2010

Я полагаю, что ваш тест неверен. Код IL из VS 2008 и VS 2010 для вашего примера программы идентичен в режиме выпуска (VS 2008 для .NET 2.0 и VS 2010 для .NET 4.0 с настройками по умолчанию). Поэтому вы не должны видеть разницу во времени между VS 2008 и VS 2010. Оба компилятора выдают следующий код:

.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

Единственное, что может отличаться - это цель платформы. VS 2010 использует x86 в качестве целевой платформы по умолчанию, тогда как VS 2008 использует AnyCPU. Если вы работаете в 64-битной системе, это приведет к тому, что различные компиляторы JIT будут использоваться для сборок VS 2008 и VS 2010. Это может привести к различным результатам, так как JIT-компиляторы разрабатываются отдельно.

5 голосов
/ 20 мая 2010

Я согласен с тем, что тест является ошибочным.

  • Это слишком коротко.
  • Как указывалось ранее, различные JIT для x86 / x64, вероятно, по-разному оптимизируют цикл.
  • Это действительно только тестирует переменные стека, которые, вероятно, JITted для быстрого доступа к регистру. Более реальный эталонный тест должен по крайней мере перемещать доступ к адресному пространству.

Большую часть дополнительного времени, вероятно, занимает слой WoW в случаях x86. Однако присущие процессам x64 неэффективности, скорее всего, перевесят накладные расходы слоя WoW в более длинном тесте, который фактически затрагивает память. Фактически, если бы эталоном был доступ к памяти (путем создания и доступа к объектам в куче), вы бы увидели преимущества оптимизации указателя слоев WoW.

0 голосов
/ 26 июля 2010

У нас та же проблема. После преобразования проекта wpf из .NET 3.5 (VS2008) в .NET 4 (VS2010) графический интерфейс гораздо менее отзывчив (задержка почти на 1 секунду для каждого клика).

После некоторого исследования мы выяснили, что это связано с тем, что Visual Studio 2010 потребляет гораздо больше ресурсов, и все идет медленнее, когда мы переводим с VS2010. Когда мы запускаем собранный проект как .exe, он снова запускается быстро.

...