C# по сравнению с C - Большое различие в производительности

Это должен быть @NgModule, а не просто NgModule.

@NgModule({
      declarations: [
        AppComponent,
        AdminComponent,
        AdminComponent1,
        AuthComponent,
        BreadcrumbsComponent,
      ],
      imports: [
        BrowserModule,
        BrowserAnimationsModule,
        FormsModule,
        ReactiveFormsModule,
        AppRoutingModule,
        SharedModule,
        NgProgressModule,
        SimpleNotificationsModule.forRoot(),
        BrowserModule,


      ],
      providers: [MenuItems, ServicesProvider, AuthGuardService, SupperAdmin, AuthLoginService,  NgProgressModule, ConfigService],
      bootstrap: [AppComponent]
    })

Метаданные используются для украшения класса, чтобы он мог настроить ожидаемое поведение класса. Мы используем синтаксис Typescript и присоединяем классы с метаданными, используя функцию декоратора. Чтобы сделать класс компонентом, мы добавляем декоратор @Component, как показано в следующем коде:

@Component({...})
export class FirstComponent {...}
92
задан John 26 March 2009 в 16:53
поделиться

13 ответов

Так как Вы никогда не используете 'корень', компилятор, возможно, удалял вызов для оптимизации метода.

Вы могли попытаться накопить значения квадратного корня в аккумулятор, распечатать его в конце метода и видеть то, что продолжается.

Редактирование: см. ответ Jalf ниже

60
ответ дан Community 24 November 2019 в 06:22
поделиться

Необходимо сравнивать сборки отладки. Я просто скомпилировал Ваш код C и добрался

Time elapsed: 0.000000

Если Вы не включаете оптимизацию, любые сравнивающие Вас делают абсолютно бесполезно. (И если Вы действительно включаете оптимизацию, цикл оптимизирован далеко. Таким образом, Ваш код сравнительного тестирования испорчен также. Необходимо вынудить это выполнить цикл, обычно путем подведения результата или подобный, и распечатывания его в конце),

Кажется, что то, что Вы измеряете, в основном, "какой компилятор вставляет большую часть отладки наверху". И оказывается, что ответ является C. Но это не говорит нам, какая программа является самой быстрой. Поскольку, когда Вы хотите скорость, Вы включаете оптимизацию.

Между прочим, Вы сохраните себя много головных болей в конечном счете при отказе от какого-либо понятия языков, являющихся "быстрее", чем каждый другие. C# больше не имеет скорость, чем английский язык.

Существуют определенные вещи на языке C, который был бы эффективен даже в наивном неоптимизирующем компиляторе, и существуют другие, который полагается в большой степени на компилятор для оптимизации всего далеко. И конечно, то же идет для C# или любого другого языка.

Скорость выполнения определяется:

  • платформа Вы работаете (ОС, аппаратные средства, другое программное обеспечение, работающее на системе)
  • компилятор
  • Ваш исходный код

Хороший компилятор C# приведет к эффективному коду. Плохой компилятор C сгенерирует медленный код. Что относительно компилятора C, который сгенерировал код C#, который Вы могли затем пробежать компилятор C#? Как быстро, который работал бы? Языки не имеют скорости. Ваш код делает.

160
ответ дан jalf 24 November 2019 в 06:22
поделиться

Я сохраню это резюме, это уже отмечено, ответил. C# имеет большое преимущество наличия четко определенной модели с плавающей точкой. Это просто, оказывается, соответствует собственному режиму работы FPU и системы команд SSE на x86 и x64 процессорах. Никакое совпадение там. Дрожание компилирует Математику. Sqrt () к нескольким встроенным инструкциям.

Собственный C/C++ обременен годами назад совместимости./fp:precise,/fp:fast и опции компиляции/fp:strict являются самыми видимыми. Соответственно, это должно вызвать функцию CRT, которая реализует sqrt () и проверяет выбранные опции с плавающей точкой скорректировать результат. Это медленно.

115
ответ дан Hans Passant 24 November 2019 в 06:22
поделиться

мое первое предположение является компиляторной оптимизацией, потому что Вы никогда не используете корень. Вы просто присваиваете его, затем перезаписываете его снова и снова.

Править: чертовски, избитый на 9 секунд!

10
ответ дан Neil N 24 November 2019 в 06:22
поделиться

Чтобы видеть, оптимизируется ли цикл далеко, попытайтесь изменить свой код на

root += Math.Sqrt(i);

ответ так же в коде C, и затем печатает значение корня вне цикла.

7
ответ дан 24 November 2019 в 06:22
поделиться

Возможно, c# компилятор замечает, что Вы не используете корень нигде, таким образом, он просто пропускает целое для цикла.:)

Это не может иметь место, но я подозреваю то, что причина, это - зависящий от реализации компилятор. Попытайтесь компилировать Вас программа C с компилятором Microsoft (cl.exe, доступный как часть win32 sdk) с режимом Release и оптимизацией. Я держал пари, что Вы будете видеть улучшение перфекта по сравнению с другим компилятором.

Править: Я не думаю, что компилятор может просто оптимизировать для цикла, потому что он должен был бы знать ту Математику. Sqrt () не имеет никаких побочных эффектов.

6
ответ дан i_am_jorf 24 November 2019 в 06:22
поделиться

Независимо от того, что различное время может быть, то "прошедшее время" недопустимо. Это только было бы допустимое, если можно гарантировать что обе программы, запущенные при тех же самых условиях.

Возможно, необходимо попробовать победу. эквивалентный $/usr/bin/time my_cprog;/usr/bin/time my_csprog

5
ответ дан Tom 24 November 2019 в 06:22
поделиться

Я соединил (на основе Вашего кода) два более сопоставимых теста в C и C#. Эти два пишут меньший массив с помощью оператора модуля для индексации (это добавляет немного служебное, но эй, мы пытаемся сравнить производительность [на сыром уровне]).

C код:

#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <math.h>

void main()
{
    int count = (int)1e8;
    int subcount = 1000;
    double* roots = (double*)malloc(sizeof(double) * subcount);
    clock_t start = clock();
    for (int i = 0 ; i < count; i++)
    {
        roots[i % subcount] = sqrt((double)i);
    }
    clock_t end = clock();
    double length = ((double)end - start) / CLOCKS_PER_SEC;
    printf("Time elapsed: %f\n", length);
}

В C#:

using System;

namespace CsPerfTest
{
    class Program
    {
        static void Main(string[] args)
        {
            int count = (int)1e8;
            int subcount = 1000;
            double[] roots = new double[subcount];
            DateTime startTime = DateTime.Now;
            for (int i = 0; i < count; i++)
            {
                roots[i % subcount] = Math.Sqrt(i);
            }
            TimeSpan runTime = DateTime.Now - startTime;
            Console.WriteLine("Time elapsed: " + Convert.ToString(runTime.TotalMilliseconds / 1000));
        }
    }
}

Эти тесты пишут данные в массив (таким образом, времени выполнения.NET нельзя позволить отобрать sqrt op), хотя массив значительно меньше (не хотел использовать чрезмерную память). Я скомпилировал их в конфигурации выпуска и выполнил их из консоли (вместо того, чтобы запуститься через VS).

На моем компьютере программа C# варьируется между 6,2 и 6,9 секундами, в то время как версия C варьируется между 6,9 и 7.1.

5
ответ дан Cecil Has a Name 24 November 2019 в 06:22
поделиться

Если Вы просто одноэтапный код на уровне ассемблера, включая продвижение через стандартную программу квадратного корня, Вы, вероятно, получите ответ на свой вопрос.

Никакая потребность в образованном предположении.

5
ответ дан Mike Dunlavey 24 November 2019 в 06:22
поделиться

Другой фактор, который может быть проблемой здесь, - то, что компилятор C компилирует в универсальный собственный код для семейства процессоров, для которого Вы нацелены, тогда как MSIL генерировал при компиляции кода C#, затем JIT, скомпилированный для предназначения для точного процессора, который Вы имеете вместе с любыми оптимизациями, которые могут быть возможными. Таким образом, собственный код, сгенерированный от C#, может быть значительно быстрее, чем C.

2
ответ дан David M 24 November 2019 в 06:22
поделиться

Мне казалось бы, что это не имеет отношения к самим языкам, скорее это относится к различным реализациям функции квадратного корня.

1
ответ дан Jack Ryan 24 November 2019 в 06:22
поделиться

На самом деле парни, цикл не оптимизируется далеко. Я скомпилировал код John's и исследовал получающийся .exe. Кишки цикла следующие:

 IL_0005:  stloc.0
 IL_0006:  ldc.i4.0
 IL_0007:  stloc.1
 IL_0008:  br.s       IL_0016
 IL_000a:  ldloc.1
 IL_000b:  conv.r8
 IL_000c:  call       float64 [mscorlib]System.Math::Sqrt(float64)
 IL_0011:  pop
 IL_0012:  ldloc.1
 IL_0013:  ldc.i4.1
 IL_0014:  add
 IL_0015:  stloc.1
 IL_0016:  ldloc.1
 IL_0017:  ldc.i4     0x5f5e100
 IL_001c:  ble.s      IL_000a

Если время выполнения не достаточно умно, чтобы понять, что цикл ничего не делает и пропускает его?

Править: Изменение C#, чтобы быть:

 static void Main(string[] args)
 {
      DateTime startTime = DateTime.Now;
      double root = 0.0;
      for (int i = 0; i <= 100000000; i++)
      {
           root += Math.Sqrt(i);
      }
      System.Console.WriteLine(root);
      TimeSpan runTime = DateTime.Now - startTime;
      Console.WriteLine("Time elapsed: " +
          Convert.ToString(runTime.TotalMilliseconds / 1000));
 }

Результаты во время протекли (на моей машине) идущий от 0,047 до 2,17. Но это - просто издержки добавления 100 миллионов операторы сложения?

1
ответ дан Dana 24 November 2019 в 06:22
поделиться

Я разработчик C++ и C#. Я разрабатываю приложения на C# со времен первой бета-версии фреймворка .NET и имею более чем 20-летний опыт разработки приложений на C++. Во-первых, код на C# НИКОГДА не будет быстрее, чем приложение на C++, но я не буду вдаваться в долгие рассуждения об управляемом коде, о том, как он работает, об уровне inter-op, о внутреннем управлении памятью, о системе динамических типов и сборщике мусора. Тем не менее, позвольте мне продолжить, сказав, что все приведенные здесь эталоны дают НЕПРАВИЛЬНЫЕ результаты.

Позвольте мне объяснить: Первое, что нам нужно рассмотреть, это JIT-компилятор для C# (.NET Framework 4). Теперь JIT производит родной код для CPU, используя различные алгоритмы оптимизации (которые, как правило, более агрессивны, чем стандартный оптимизатор C++, поставляемый с Visual Studio), и набор инструкций, используемый компилятором .NET JIT, является более близким отражением реального CPU на машине, поэтому определенные замены в машинном коде могут быть сделаны для сокращения тактовых циклов и улучшения попадания в кэш конвейера CPU, а также для дальнейшей оптимизации гиперпоточности, такой как переупорядочивание инструкций и улучшения, связанные с предсказанием ветвлений.

Это означает, что если вы не скомпилируете свое приложение на C++, используя правильные параметры для сборки RELEASE (а не для сборки DEBUG), то ваше приложение на C++ может работать медленнее, чем соответствующее приложение на базе C# или .NET. При задании свойств проекта для вашего приложения на C++ убедитесь, что вы включили "полную оптимизацию" и "любимый быстрый код". Если у вас 64-битная машина, вы ДОЛЖНЫ указать в качестве целевой платформы генерацию x64, иначе ваш код будет выполняться через подуровень преобразования (WOW64), что существенно снизит производительность.

После выполнения правильных оптимизаций в компиляторе я получил .72 секунды для приложения C++ и 1.16 секунды для приложения C# (оба в релизной сборке). Поскольку приложение C# очень простое и выделяет память, используемую в цикле, в стеке, а не в куче, оно работает намного лучше, чем реальное приложение, работающее с объектами, тяжелыми вычислениями и с большими наборами данных. Таким образом, приведенные цифры являются оптимистичными, смещенными в сторону C# и фреймворка .NET. Даже с учетом этого перекоса приложение на C++ завершается чуть более чем за половину времени, чем аналогичное приложение на C#. Имейте в виду, что компилятор Microsoft C++, который я использовал, не имел нужных оптимизаций конвейера и гиперпоточности (используя WinDBG для просмотра инструкций ассемблера).

Теперь, если мы используем компилятор Intel (который, кстати, является промышленным секретом для создания высокопроизводительных приложений на процессорах AMD/Intel), тот же код выполняется за .54 секунды для исполняемого файла C++ против .72 секунд при использовании Microsoft Visual Studio 2010. Таким образом, конечный результат составляет .54 секунды для C++ и 1.16 секунды для C#. Таким образом, код, созданный компилятором .NET JIT, занимает в 214% раз больше времени, чем исполняемый файл C++. Большая часть времени, затраченного на эти .54 секунды, была потрачена на получение времени от системы, а не внутри самого цикла!

Что также отсутствует в статистике, так это время запуска и очистки, которые не включены в тайминги. Приложения на C#, как правило, тратят гораздо больше времени на запуск и завершение работы, чем приложения на C++. Причина этого сложна и связана с процедурами проверки кода во время выполнения .NET и подсистемой управления памятью, которая выполняет много работы в начале (и, соответственно, в конце) программы для оптимизации выделения памяти и сборщика мусора.

При измерении производительности C++ и .NET IL важно посмотреть на код сборки, чтобы убедиться, что ВСЕ вычисления там есть. Я обнаружил, что без введения дополнительного кода в C#, большая часть кода в приведенных выше примерах была фактически удалена из двоичного файла. То же самое происходило и с C++, когда вы использовали более агрессивный оптимизатор, такой как тот, что поставляется с компилятором Intel C++. Результаты, которые я привел выше, на 100% верны и подтверждены на уровне ассемблера.

Основная проблема многих форумов в интернете заключается в том, что многие новички слушают маркетинговую пропаганду Microsoft, не понимая технологии, и делают ложные заявления о том, что C# быстрее C++. Утверждение заключается в том, что в теории, C# быстрее, чем C++, потому что JIT-компилятор может оптимизировать код для процессора. Проблема с этой теорией заключается в том, что в .NET-фреймворке есть много "сантехники", которая замедляет производительность; "сантехники", которой нет в приложении на C++. Кроме того, опытный разработчик знает, какой компилятор следует использовать для данной платформы, и использует соответствующие флаги при компиляции приложения. На платформах Linux или open source это не является проблемой, поскольку вы можете распространять исходный код и создавать инсталляционные скрипты, которые компилируют код с использованием соответствующей оптимизации. На платформе windows или платформе с закрытым исходным кодом вам придется распространять несколько исполняемых файлов, каждый с определенной оптимизацией. Двоичные файлы windows, которые будут развернуты, основаны на процессоре, обнаруженном программой установки msi (с использованием пользовательских действий).

55
ответ дан 24 November 2019 в 06:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: