Подтвердить что ты не робот

Продолжительность выполнения .NET 4.0 медленнее, чем время выполнения .NET 2.0?

После того, как я обновил свои проекты до .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
    • Целевая структура 2.0: ~ 0.25 секунд
    • Target Framework 3.0: ~ 0.25 секунд
    • Target Framework 3.5: ~ 0.25 секунд
  • VS2010
    • Целевая структура 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? и между различными целевыми структурами внутри самого VS2010?

4b9b3361

Ответ 1

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

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

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

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

EDIT: согласно комментариям Дастина, запуск x86, а не x64 может иметь преимущества производительности с точки зрения более эффективного использования памяти (более короткие ссылки).

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

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

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

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

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

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

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

Ответ 2

Я считаю, что ваш тест ошибочен. Код 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 VS против VS 2010. Это может привести к разным результатам, поскольку компиляторы JIT разрабатываются отдельно.

Ответ 3

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

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

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

Ответ 4

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

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