هل يؤدي استخدام السياق غير المحدد إلى الإضرار بالأداء أو قابلية النقل في ج#?
-
27-10-2019 - |
سؤال
أريد تنفيذ وظيفة التجزئة السريعة التي سوف تستخدم int
نوع البيانات والاعتماد على تجاوز عدد صحيح.تقول مسن أنه من أجل ضمان أن الفيضانات لا تؤدي إلى استثناءات لا بد لي من استخدامها unchecked
كتل لهذا الرمز.
لنفترض أنني تحيط فقط أن حساب في unchecked
منع.هل سيواجه الكود الخاص بي أي مشاكل في الأداء أو قابلية النقل بسبب ذلك?
المحلول
من الناحية الفنية فقط checked
يجب أن تبطئ الكتل.لذلك أنا لا أعتقد أن unchecked
كتلة (كتلة حيث الإطار يجب أن تفعل أقل الشيكات) يمكن أن تبطئ.إنه ليس مفتاح سياق أو شيء مشابه.جيت ببساطة لا تنبعث منها تعليمات للتحقق من تجاوز / تحت التدفق.الآن ، من الواضح إذا كان شخص ما خلق معالج" خاص " حيث يجب محاكاة تجاوز واستدار أحادية على ذلك ، أو حيث تجاوز يسبب نتائج مختلفة من على معالجات إنتل ، و unchecked
كتلة سيكون أبطأ (لأن جيت يجب أن "محاكاة" ذلك).ولكن لاحظ أن أنواع قاعدة صافي يتم تعريفها في إسما قياسي.يجب أن تستند السجلات الموقعة إلى مكملين على سبيل المثال ، ويجب أن يكون حجمها 8 ، 16 ، 32 ، 64 بت.لا توجد مساحة كبيرة للمعالجات "الغريبة" التي تستخدم 36 بت الأعداد الصحيحة.
نصائح أخرى
فحص إضافة تعليمات عملية واحدة فقط:
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
}
وكقاعدة عامة يمكنك أن تتوقع الحساب دون رادع ليكون أسرع قليلا ، لكنه الى حد كبير لا يستحق طرح السؤال المعاكس لك (بمعنى."سوف باستخدام فحص يضر أدائي?").
فحص ودون رادع يعني فقط أن هناك قواعد مختلفة قليلا عن كيفية مثل المشغلين +
, *
, ، و -
يتم التعامل معها ، ويجب عليك استخدام واحد مناسب للحالة في متناول اليد.
في هذه الحالة ، أنت بالتأكيد تريد دون رادع ، لذلك يجب عليك ذكر ذلك في التعليمات البرمجية الخاصة بك.هذا في الواقع الزيادات قابلية النقل ، حيث سيكون لديك بعد ذلك نفس السلوك مهما كانت مفاتيح التحويل البرمجي المستخدمة معها.
لقد أنشأت طريقتين ، واحدة ملفوفة بواسطة checked
وآخر من قبل unchecked
.من خلال النظر في ايل فرق واحد فقط هو mul
العملية (التي تقوم بعملية الضرب) ، لفحصها mul.ovf
يتم إنشاؤه ولم يتم التحقق منه - mul
.
لتلخيص ، وأعتقد أن الفرق في عملية وحدة المعالجة المركزية واحدة لا يجعل أي تأثير على الأداء ، والفرق الوحيد سيكون في حالة تجاوز باستخدام checked
- في هذه الحالة سيتم إنشاء أوفيرفلوكسيبتيون التي من الواضح أن تبطئ التنفيذ.
تعليمات اللغة المتوسطة التالية من ميكروسوفت (مسيل) رمي أوفيرفلوكسيبتيون:
- مول.عوف.
- ...
[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);
}
}
ثم باستخدام إلداسم انظر إيل:
فحص():
// 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(...)