ठीक है, जिस तरह से आप चीजों को टाइम कर रहे हैं वह मुझे बहुत बुरा लग रहा है। यह पूरी तरह से पूरे लूप के लिए बहुत अधिक समझदार होगा:
var stopwatch = Stopwatch.StartNew();
for (int i = 1; i < 100000000; i++)
{
Fibo(100);
}
stopwatch.Stop();
Console.WriteLine("Elapsed time: {0}", stopwatch.Elapsed);
इस तरह आप छोटे समय, दयापूर्ण अंकगणित और संचित त्रुटि की दया पर नहीं हैं।
उस परिवर्तन को करने के बाद, देखें कि क्या "नॉन-कैच" संस्करण "कैच" संस्करण की तुलना में अभी भी धीमा है।
संपादित करें: ठीक है, मैंने इसे स्वयं आजमाया है - और मैं उसी परिणाम को देख रहा हूं। बहुत अजीब। मुझे आश्चर्य है कि क्या कोशिश / पकड़ कुछ खराब inlining को अक्षम कर रही [MethodImpl(MethodImplOptions.NoInlining)]
थी , लेकिन इसके बजाय उपयोग करने से मदद नहीं मिली ...
मूल रूप से आपको कॉर्डबग के तहत अनुकूलित JITted कोड को देखने की आवश्यकता होगी, मुझे संदेह है ...
संपादित करें: जानकारी के कुछ और बिट्स:
- बस
n++;
लाइन के आसपास की कोशिश / पकड़ लाना अभी भी प्रदर्शन में सुधार करता है, लेकिन पूरे ब्लॉक के आसपास इसे डालकर नहीं
- यदि आप एक विशिष्ट अपवाद को पकड़ते हैं (
ArgumentException
मेरे परीक्षणों में) यह अभी भी तेज है
- यदि आप कैच ब्लॉक में अपवाद प्रिंट करते हैं तो यह अभी भी तेज है
- यदि आप कैच ब्लॉक में अपवाद को हटा देते हैं तो यह फिर से धीमा हो जाता है
- यदि आप कैच ब्लॉक के बजाय अंततः ब्लॉक का उपयोग करते हैं तो यह फिर से धीमा हो जाता है
- यदि आप एक अंतिम ब्लॉक के साथ-साथ एक कैच ब्लॉक का उपयोग करते हैं, तो यह तेज है
अजीब...
संपादित करें: ठीक है, हम disassembly है ...
यह C # 2 कंपाइलर और .NET 2 (32-बिट) सीएलआर का उपयोग कर रहा है, mdbg के साथ असंतुष्ट (जैसा कि मेरी मशीन पर कॉर्डबग नहीं है)। मैं अभी भी डिबगर के तहत समान प्रदर्शन प्रभाव देखता हूं। फास्ट संस्करण try
केवल एक catch{}
हैंडलर के साथ चर घोषणाओं और रिटर्न स्टेटमेंट के बीच सब कुछ के आसपास एक ब्लॉक का उपयोग करता है । स्पष्ट रूप से धीमा संस्करण कोशिश / पकड़ के बिना समान है। कॉलिंग कोड (यानी मुख्य) दोनों मामलों में समान है, और इसमें एक ही विधानसभा प्रतिनिधित्व है (इसलिए यह एक अशुद्धि मुद्दा नहीं है)।
तेज संस्करण के लिए डिसबेल्ड कोड:
[0000] push ebp
[0001] mov ebp,esp
[0003] push edi
[0004] push esi
[0005] push ebx
[0006] sub esp,1Ch
[0009] xor eax,eax
[000b] mov dword ptr [ebp-20h],eax
[000e] mov dword ptr [ebp-1Ch],eax
[0011] mov dword ptr [ebp-18h],eax
[0014] mov dword ptr [ebp-14h],eax
[0017] xor eax,eax
[0019] mov dword ptr [ebp-18h],eax
*[001c] mov esi,1
[0021] xor edi,edi
[0023] mov dword ptr [ebp-28h],1
[002a] mov dword ptr [ebp-24h],0
[0031] inc ecx
[0032] mov ebx,2
[0037] cmp ecx,2
[003a] jle 00000024
[003c] mov eax,esi
[003e] mov edx,edi
[0040] mov esi,dword ptr [ebp-28h]
[0043] mov edi,dword ptr [ebp-24h]
[0046] add eax,dword ptr [ebp-28h]
[0049] adc edx,dword ptr [ebp-24h]
[004c] mov dword ptr [ebp-28h],eax
[004f] mov dword ptr [ebp-24h],edx
[0052] inc ebx
[0053] cmp ebx,ecx
[0055] jl FFFFFFE7
[0057] jmp 00000007
[0059] call 64571ACB
[005e] mov eax,dword ptr [ebp-28h]
[0061] mov edx,dword ptr [ebp-24h]
[0064] lea esp,[ebp-0Ch]
[0067] pop ebx
[0068] pop esi
[0069] pop edi
[006a] pop ebp
[006b] ret
धीमे संस्करण के लिए डिसबेल्ड कोड:
[0000] push ebp
[0001] mov ebp,esp
[0003] push esi
[0004] sub esp,18h
*[0007] mov dword ptr [ebp-14h],1
[000e] mov dword ptr [ebp-10h],0
[0015] mov dword ptr [ebp-1Ch],1
[001c] mov dword ptr [ebp-18h],0
[0023] inc ecx
[0024] mov esi,2
[0029] cmp ecx,2
[002c] jle 00000031
[002e] mov eax,dword ptr [ebp-14h]
[0031] mov edx,dword ptr [ebp-10h]
[0034] mov dword ptr [ebp-0Ch],eax
[0037] mov dword ptr [ebp-8],edx
[003a] mov eax,dword ptr [ebp-1Ch]
[003d] mov edx,dword ptr [ebp-18h]
[0040] mov dword ptr [ebp-14h],eax
[0043] mov dword ptr [ebp-10h],edx
[0046] mov eax,dword ptr [ebp-0Ch]
[0049] mov edx,dword ptr [ebp-8]
[004c] add eax,dword ptr [ebp-1Ch]
[004f] adc edx,dword ptr [ebp-18h]
[0052] mov dword ptr [ebp-1Ch],eax
[0055] mov dword ptr [ebp-18h],edx
[0058] inc esi
[0059] cmp esi,ecx
[005b] jl FFFFFFD3
[005d] mov eax,dword ptr [ebp-1Ch]
[0060] mov edx,dword ptr [ebp-18h]
[0063] lea esp,[ebp-4]
[0066] pop esi
[0067] pop ebp
[0068] ret
प्रत्येक मामले में *
डिबगर साधारण "स्टेप-इन" में प्रवेश करता है।
संपादित करें: ठीक है, मैंने अब कोड के माध्यम से देखा है और मुझे लगता है कि मैं देख सकता हूं कि प्रत्येक संस्करण कैसे काम करता है ... और मेरा मानना है कि धीमी संस्करण धीमा है क्योंकि यह कम रजिस्टरों और अधिक स्टैक स्पेस का उपयोग करता है। के छोटे मूल्यों n
के लिए संभवतः तेज है - लेकिन जब लूप समय के थोक लेता है, यह धीमा है।
संभवतः कोशिश / पकड़ ब्लॉक अधिक रजिस्टरों को बचाने और बहाल करने के लिए मजबूर करता है, इसलिए जेआईटी लूप के लिए भी उपयोग करता है ... जो कि समग्र प्रदर्शन में सुधार के लिए होता है। यह स्पष्ट नहीं है कि JIT के लिए "सामान्य" कोड में कई रजिस्टरों का उपयोग नहीं करना उचित निर्णय है या नहीं ।
संपादित करें: बस मेरे x64 मशीन पर यह कोशिश की। इस कोड पर x86 सीएलआर की तुलना में x64 सीएलआर बहुत तेज (लगभग 3-4 गुना तेज) है, और x64 के तहत कोशिश / कैच ब्लॉक ध्यान देने योग्य अंतर नहीं करता है।