Влияет ли использование непроверенного контекста на производительность или переносимость в C #? - PullRequest
7 голосов
/ 20 октября 2011

Я хочу реализовать быструю функцию хеширования, которая будет использовать тип данных int и полагаться на целочисленное переполнение. MSDN говорит, что для гарантии того, что переполнения не вызовут исключения, я должен использовать для этого кода блоки unchecked.

Предположим, я окружаю только эти вычисления в unchecked блоке. Из-за этого у моего кода будут проблемы с производительностью или переносимостью?

Ответы [ 4 ]

8 голосов
/ 20 октября 2011

Как правило, вы можете ожидать, что непроверенная арифметика будет немного быстрее, но почти никогда не стоит задавать обратный вопрос (а именно: повредит ли использование метки в моей производительности? ").

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

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

8 голосов
/ 20 октября 2011

Технически только блоки checked должны замедляться. Поэтому я не думаю, что блок unchecked (блок, в котором фреймворк должен выполнять меньше проверок) может замедлиться. Это не переключение контекста или что-то подобное. JIT просто не выдает инструкции для проверки на переполнение / переполнение. Теперь ясно, что если кто-то создал «специальный» процессор, где переполнение должно быть смоделировано, и перенес на него моно, или если переполнение приводит к результатам, отличным от результатов на процессорах Intel, блок unchecked будет медленнее (потому что JIT должен будет » симулировать "это". Но обратите внимание, что базовые типы .NET определены в стандарте ECMA . Например, подписанные целые числа должны быть основаны на двух дополнениях, а их размер должен составлять 8, 16, 32, 64 бита. Для «странных» процессоров, которые используют 36-битные целые числа .

, не так много места.
7 голосов
/ 10 марта 2016

проверено добавить только одну инструкцию процесса:

checked
{
    int y = x * x;
05297978  mov         eax,dword ptr [ebp-10h]  
0529797B  imul        eax,dword ptr [ebp-10h]  
0529797F  jno         05297986  //if not overflow: goto 05297986
05297981  call        72A29522  //invoke exception
05297986  mov         dword ptr [ebp-14h],eax  
}

unchecked
{
    int yy = xx * xx;
0529799E  mov         eax,dword ptr [ebp-18h]  
052979A1  imul        eax,dword ptr [ebp-18h]  
052979A5  mov         dword ptr [ebp-1Ch],eax  
}
4 голосов
/ 20 октября 2011

Я создал два метода, один обернутый checked, а другой * unchecked.Если посмотреть на IL, единственное отличие - это операция mul (которая выполняет операцию умножения), для проверенного генерируется mul.ovf, а для непроверенного - mul.

Подводя итог, я считаю, что разница в одной операции ЦП не влияет на производительность, единственное отличие будет в случае переполнения при использовании checked - в этом случае будет сгенерировано OverflowException, которое, очевидно, медленнозавершение выполнения.

MSDN:

Следующие инструкции Microsoft на промежуточном языке (MSIL) генерируют исключение OverflowException:

  • mul.OVF.
  • ...
[Test]
public void Checked()
{
    checked
    {
        int i = int.MaxValue;
        i = i * 100;
        Debug.WriteLine(i);
    }
}

[Test]
public void UnChecked()
{
    unchecked
    {
        int i = int.MaxValue;
        i = i * 100;
        Debug.WriteLine(i);
    }            
}

И затем с помощью ILDASM см. IL:

CHECKED ():

// Code size       27 (0x1b)
  .maxstack  2
  .locals init ([0] int32 i)
  IL_0000:  nop
  IL_0001:  nop
  IL_0002:  ldc.i4     0x7fffffff
  IL_0007:  stloc.0
  IL_0008:  ldloc.0
  IL_0009:  ldc.i4.s   100
  **IL_000b:  mul.ovf** !!!
  IL_000c:  stloc.0
  IL_000d:  ldloc.0
  IL_000e:  box        [mscorlib]System.Int32
  IL_0013:  call       void [System]System.Diagnostics.Debug::WriteLine ...

НЕПРОВЕРЕНО ():

  // Code size       27 (0x1b)
  .maxstack  2
  .locals init ([0] int32 i)
  IL_0000:  nop
  IL_0001:  nop
  IL_0002:  ldc.i4     0x7fffffff
  IL_0007:  stloc.0
  IL_0008:  ldloc.0
  IL_0009:  ldc.i4.s   100
  **IL_000b:  mul** !!!
  IL_000c:  stloc.0
  IL_000d:  ldloc.0
  IL_000e:  box        [mscorlib]System.Int32
  IL_0013:  call       void [System]System.Diagnostics.Debug::WriteLine(...)
...