Есть ли какое-либо различие в производительности между ++ я и я ++ в C#?

Быстрый совет, который меня опрокинул: если вы ссылаетесь на компоновщик как «gcc» или «g ++», то использование «--start-group» и «--end-group» не будет передавать эти параметры до линкера - и не будет отмечена ошибка.

Вам нужно записать их как «-Wl, - start-group» и т. Д., Чтобы сообщить GCC передать аргумент через к компоновщику.

47
задан Anton 22 January 2009 в 13:36
поделиться

10 ответов

Нет никакого различия в сгенерированном промежуточном коде для ++ я и я ++ в этом случае. Учитывая эту программу:

class Program
{
    const int counter = 1024 * 1024;
    static void Main(string[] args)
    {
        for (int i = 0; i < counter; ++i)
        {
            Console.WriteLine(i);
        }

        for (int i = 0; i < counter; i++)
        {
            Console.WriteLine(i);
        }
    }
}

сгенерированный код IL является тем же для обоих циклов:

  IL_0000:  ldc.i4.0
  IL_0001:  stloc.0
  // Start of first loop
  IL_0002:  ldc.i4.0
  IL_0003:  stloc.0
  IL_0004:  br.s       IL_0010
  IL_0006:  ldloc.0
  IL_0007:  call       void [mscorlib]System.Console::WriteLine(int32)
  IL_000c:  ldloc.0
  IL_000d:  ldc.i4.1
  IL_000e:  add
  IL_000f:  stloc.0
  IL_0010:  ldloc.0
  IL_0011:  ldc.i4     0x100000
  IL_0016:  blt.s      IL_0006
  // Start of second loop
  IL_0018:  ldc.i4.0
  IL_0019:  stloc.0
  IL_001a:  br.s       IL_0026
  IL_001c:  ldloc.0
  IL_001d:  call       void [mscorlib]System.Console::WriteLine(int32)
  IL_0022:  ldloc.0
  IL_0023:  ldc.i4.1
  IL_0024:  add
  IL_0025:  stloc.0
  IL_0026:  ldloc.0
  IL_0027:  ldc.i4     0x100000
  IL_002c:  blt.s      IL_001c
  IL_002e:  ret

Однако это возможно (хотя очень вряд ли), что JIT-компилятор может сделать некоторую оптимизацию в определенных контекстах, которые будут способствовать одной версии по другому. Если бы существует такая оптимизация, тем не менее, она, вероятно, только влияла бы на финал (или возможно первое) повторение цикла.

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

36
ответ дан Jim Mischel 7 November 2019 в 23:30
поделиться

А-ч... Откройтесь снова. Хорошо. Вот соглашение.

ILDASM является запуском, но не концом. Ключ: Что JIT генерирует для ассемблерного кода?

Вот то, что Вы хотите сделать.

Берут пару образцов того, на что Вы пытаетесь посмотреть. Очевидно, Вы можете тактовое стеной время их, если Вы хотите - но я предполагаю, что Вы хотите знать больше, чем это.

Вот то, что не очевидно. Компилятор C# генерирует некоторые последовательности MSIL, которые неоптимальны в большом количестве ситуаций. JIT это настроилось для контакта с ними и причудами с других языков. Проблема: Только 'причуды', которые кто-то заметил, были настроены.

Вы действительно хотите сделать образец, который имеет Ваши реализации для попытки, возвраты назад до основного (или везде, где), Сон () s, или что-то, где можно присоединить отладчик, затем выполнить стандартные программы снова.

Вы НЕ хотите запускать код под отладчиком, или JIT генерирует неоптимизированный код - и это кажется, что Вы хотите знать, как это будет вести себя в реальной среде. JIT делает это, чтобы максимизировать информацию об отладке и минимизировать текущее исходное местоположение от 'перехода вокруг'. Никогда не запускайте оценку перфекта под отладчиком.

хорошо. Таким образом, как только код работал однажды (т.е.: JIT генерировал код для него), затем присоедините отладчик во время сна (или безотносительно). Тогда посмотрите на x86/x64, который был сгенерирован для этих двух стандартных программ.

Мой пищеварительный тракт говорит мне, что, если Вы используете ++ i/i ++, поскольку Вы описали - т.е.: в одиноком выражении, где результат rvalue не снова используется - не будет различия. Но не будет это быть забавой пойти узнает и видит весь аккуратный материал!:)

7
ответ дан Joe 7 November 2019 в 23:30
поделиться

Поскольку Jim Mischel показал , компилятор генерирует идентичный MSIL для двух способов записать для цикла.

, Но это - он тогда: нет никакой причины размышлять о JIT или выполнить измерения скорости. Если две строки кода генерируют идентичный MSIL, мало того, что они будут работать тождественно, они эффективно идентичны.

Никакой возможный JIT не был бы в состоянии различать циклы, таким образом, сгенерированный машинный код должен обязательно быть идентичным, также.

5
ответ дан Community 7 November 2019 в 23:30
поделиться

Парни, парни, "ответы" для C и C++.

C# является различным животным.

Использование ILDASM для рассмотрения скомпилированного вывода, чтобы проверить, существует ли различие в MSIL.

4
ответ дан dan 7 November 2019 в 23:30
поделиться

Имеет конкретная часть кода и выпуска CLR в памяти? Если так, сравните его. В противном случае забудьте об этом. Микрооптимизация и все это... Кроме того, Вы не можете даже быть уверены, что различный выпуск CLR приведет к тому же результату.

3
ответ дан Michael Borgwardt 7 November 2019 в 23:30
поделиться

В дополнение к другим ответам может быть различие , если Ваш i не int . В C++ , если это - объект класса, которому перегрузили операторы ++() и ++(int), тогда это может иметь значение, и возможно побочный эффект. Производительность ++i должна быть лучше в этом случае (иждивенец на реализации).

2
ответ дан Hosam Aly 7 November 2019 в 23:30
поделиться

Согласно этот ответ , я ++ использую одну инструкцию по ЦП больше, чем ++ я. Но ли это приводит к различию в производительности, я не знаю.

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

0
ответ дан Community 7 November 2019 в 23:30
поделиться
  static void Main(string[] args) {
     var sw = new Stopwatch(); sw.Start();
     for (int i = 0; i < 2000000000; ++i) { }
     //int i = 0;
     //while (i < 2000000000){++i;}
     Console.WriteLine(sw.ElapsedMilliseconds);

Среднее число от 3 выполнений:
для со мной ++: 1307 для с ++ я: 1314

, в то время как со мной ++: 1261, в то время как с ++ я: 1276

Это - Celeron D на уровне 2,53 ГГц. Каждое повторение взяло приблизительно 1,6 цикла ЦП. То, что или средства, что ЦП выполнял больше чем 1 инструкцию каждый цикл или что JIT-компилятор развернул циклы. Различие между мной ++ и ++ я был только 0,01 циклами ЦП на повторение, вероятно, вызванное службами ОС в фоновом режиме.

0
ответ дан ggf31416 7 November 2019 в 23:30
поделиться

Если Вы задаете этот вопрос, Вы пытаетесь решить неправильную проблему.

первый вопрос спросить, "как я улучшаю удовлетворенность потребителя своим программным обеспечением, заставляя его работать быстрее?" и ответ является почти никогда "использованием ++ я вместо меня ++" или наоборот.

От Кодирования сообщения Ужаса" Аппаратные средства являются Дешевыми, Программисты Дороги ":

Правила Оптимизации:
Правило 1: не делайте этого.
Правило 2 (только для экспертов): еще не делайте этого.
- M.A. Jackson

я прочитал правило 2 означать "первую запись чистый, код разъединения, который удовлетворяет потребности Вашего клиента, затем ускорьте его, где это слишком медленно". Очень маловероятно, что ++i по сравнению с i++ будет решением.

7
ответ дан Brad Larson 7 November 2019 в 23:30
поделиться

Нет никакого различия между обоими, причина находится в сравнении цикла, отдельный оператор после инкрементного/декрементного оператора. Пример;

for(int i=0; i<3; i++){
    System.out.println(i)
}

Это работает как как ниже,

, Шаг инициализирует: i = 0

Шаг Сравните: i < 3, это верно, тогда выполняются loop блок

Инкремент Шага: i = i++; или i = ++i;

Шаг Copmare Снова: Поскольку Java делает сравнение на следующем шаге. И я ++ и ++ я даю тот же результат. Например, если я = 0, после инкремента я стану 1.

Thats, почему или пред инкремент или пред инкремент сообщения ведет себя то же в цикле.

0
ответ дан 26 November 2019 в 19:49
поделиться
Другие вопросы по тегам:

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