.NET 4.0 Runtime медленнее, чем .NET 2.0 Runtime?

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

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 seconds
    • Target Framework 3.0: ~ 0,25 секунды
    • Target Framework 3.5: ~ 0,25 секунды
  • VS2010
    • Target Framework 2.0: ~3.8 seconds
    • Target Framework 3.0: ~ 3,8 секунды
    • Target Framework 3.5: ~ 1,51 секунды
    • Профиль клиента Target Framework 3.5: ~ 3,8 секунды
    • Target Framework 4.0: ~ 1,01 секунды
    • Профиль клиента целевой платформы 4.0: ~ 1,01 секунды

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

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


person DxCK    schedule 19.05.2010    source источник
comment
Вы запускаете их через отладчик в Visual Studio или запускаете приложения в режиме выпуска?   -  person Mark Redman    schedule 19.05.2010
comment
Вы тестировали несколько запусков, чтобы минимизировать внешние воздействия? В нынешнем виде результаты вполне могут быть получены исключительно случайно. Несмотря на то, что это выглядит убедительным, одиночный прогон не даст почти никакой значимости в этом тесте.   -  person Konrad Rudolph    schedule 19.05.2010
comment
Вы пробовали запускать его вне VS?   -  person eflles    schedule 19.05.2010
comment
Ваша программа-пример кажется некорректной. Тело цикла пусто и, следовательно, в основном удаляется оптимизатором.   -  person Dirk Vollmar    schedule 19.05.2010
comment
Я запускаю все тесты в режиме Release и без подключенного отладчика. Оба проекта чистые, поэтому я не думаю, что есть разница в настройках, или настройки VS2010 по умолчанию должны замедлить работу программы?: |   -  person DxCK    schedule 19.05.2010
comment
@DxCK: См. Мой отредактированный ответ. Бьюсь об заклад, вы работаете на 64-битной машине, но VS2010 строит таргетинг на x86 ...   -  person Jon Skeet    schedule 19.05.2010


Ответы (4)


Думаю, я понял.

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

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

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

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

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

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

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

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

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

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

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

person Jon Skeet    schedule 19.05.2010
comment
Может ли разница быть целевой платформой? csc.exe использует AnyCPU по умолчанию, тогда как VS 2010 изменил значение по умолчанию на x86. - person Dirk Vollmar; 19.05.2010
comment
@ 0xA3: Разве мой ответ не об этом в основном? - person Jon Skeet; 19.05.2010
comment
Да, это так, но в вашем ответе еще не говорилось об этом, когда я писал свой комментарий ;-) Я бы хотел, чтобы было мгновенное обновление, если кто-то обновит свой ответ. - person Dirk Vollmar; 19.05.2010
comment
После перехода на Any CPU у меня было ~ 0,25 секунды во всех целевых фреймворках, как и в VS2008, это круто! Он по-прежнему не объясняет разницу в производительности платформы x86 с различными целевыми платформами. - person DxCK; 19.05.2010
comment
Действительно, одной из причин изменения целевой платформы по умолчанию были сценарии «Изменить и продолжить», а также сценарии P / Invoke и COM-взаимодействия. Однако это изменение не влияет на библиотеки классов. Здесь по умолчанию все еще AnyCPU. См. connect.microsoft.com/VisualStudio/feedback/details/455333/ для более подробного объяснения. - person Dirk Vollmar; 19.05.2010
comment
FWIW, запуск процесса x86 на 64-битной машине не является неоптимальным. В общем, выполнение процесса x86 на 64-битной машине на самом деле быстрее, чем выполнение процесса x64. См. Мой ответ ниже, чтобы узнать, почему я считаю, что эталонный тест ошибочен. - person Dustin Campbell; 20.05.2010
comment
Я не уверен, как именно работает JIT, но я нахожу бинарные файлы x64, написанные на C / C ++ на 64-битной системе, быстрее. (Я пытался написать несколько генетических алгоритмов, и разница во времени между многопоточными сборками x86 и x64 составляла около 10%) - person nothrow; 08.06.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-компиляторы разрабатываются отдельно.

person Dirk Vollmar    schedule 19.05.2010

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

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

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

person Dustin Campbell    schedule 20.05.2010

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

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

person urza    schedule 26.07.2010