सी # बनाम सी - बड़ा प्रदर्शन अंतर


94

मैं Cc C # में समान कोड के बीच बड़े पैमाने पर प्रदर्शन अंतर पा रहा हूं।

सी कोड है:

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

main()
{
    int i;
    double root;

    clock_t start = clock();
    for (i = 0 ; i <= 100000000; i++){
        root = sqrt(i);
    }
    printf("Time elapsed: %f\n", ((double)clock() - start) / CLOCKS_PER_SEC);   

}

और C # (कंसोल ऐप) है:

using System;
using System.Collections.Generic;
using System.Text;

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

उपरोक्त कोड के साथ, C # 0.328125 सेकंड (रिलीज़ संस्करण) में पूरा होता है और C को चलने में 11.14 सेकंड लगते हैं।

सी को मिंगव का उपयोग करके एक विंडोज़ निष्पादन योग्य के लिए संकलित किया जा रहा है।

मैं हमेशा इस धारणा के अधीन रहा हूं कि C / C ++ तेज या कम से कम C # .net के बराबर था। क्या वास्तव में सी 30 गुना धीमी गति से चलने का कारण है?

संपादित करें: ऐसा प्रतीत होता है कि C # ऑप्टिमाइज़र रूट को हटा रहा था क्योंकि इसका उपयोग नहीं किया जा रहा था। मैंने रूट असाइनमेंट को रूट + = में बदल दिया और अंत में कुल प्रिंट किया। मैंने C को अधिकतम गति के लिए / O2 ध्वज सेट के साथ cl.exe का उपयोग करके भी संकलित किया है।

परिणाम अब हैं: 3.75 सेकंड सी 2.61 सेकंड सी # के लिए

C अभी भी अधिक समय ले रहा है, लेकिन यह स्वीकार्य है


18
मेरा सुझाव है कि आप सिर्फ एक डेटटाइम के बजाय एक स्टॉपवॉच का उपयोग करें।
एलेक्स फोर्ट

2
कौन सा संकलक झंडे? क्या दोनों अनुकूलन के साथ संकलित हैं?
जलफ

2
जब आप C ++ कंपाइलर के साथ -astast-math का उपयोग करते हैं तो क्या होगा?
डैन मैकक्लेन

10
कितना आकर्षक प्रश्न है!
रॉबर्ट एस।

4
शायद C sqrt फंक्शन C # में उतना अच्छा नहीं है। तब यह सी के साथ एक मुद्दा नहीं होगा, लेकिन इसके साथ पुस्तकालय जुड़ा हुआ है। गणित कार्यों के बिना कुछ गणना का प्रयास करें।
klew

जवाबों:


61

चूंकि आप कभी भी 'रूट' का उपयोग नहीं करते हैं, हो सकता है कि कंपाइलर आपकी विधि को अनुकूलित करने के लिए कॉल को हटा रहा हो।

आप वर्गमूल मानों को एक संचायक में संचित करने की कोशिश कर सकते हैं, इसे विधि के अंत में प्रिंट कर सकते हैं, और देखें कि क्या हो रहा है।

संपादित करें: नीचे दिए गए जलफ का जवाब देखें


1
थोड़ा सा प्रयोग बताता है कि ऐसा नहीं है। लूप के लिए कोड उत्पन्न होता है, हालांकि शायद रनटाइम इसे छोड़ने के लिए पर्याप्त स्मार्ट है। यहां तक ​​कि संचय करते हुए, C # अभी भी C
Dana

3
ऐसा लगता है कि समस्या दूसरे छोर पर है। C # सभी मामलों में यथोचित व्यवहार करता है। उनका सी कोड जाहिरा तौर पर अनुकूलन के बिना संकलित है
jalf

2
आप में से बहुत से लोग यहां बिंदु को याद कर रहे हैं। मैं ऐसे ही कई मामलों को पढ़ रहा हूँ जहाँ c # outperforms c / c ++ और हमेशा rebuttal को कुछ विशेषज्ञ स्तर के अनुकूलन को नियोजित करना है। प्रोग्रामर के 99% को इस तरह की अनुकूलन तकनीकों का उपयोग करने का ज्ञान नहीं है, ताकि उनके कोड को सी # कोड की तुलना में थोड़ा तेज चलाया जा सके। C / c ++ के मामलों का उपयोग संकीर्ण कर रहे हैं।

167

आपको डीबग बिल्ड की तुलना करनी चाहिए। मैंने अभी आपका C कोड संकलित किया, और प्राप्त किया

Time elapsed: 0.000000

यदि आप अनुकूलन को सक्षम नहीं करते हैं, तो आपके द्वारा किया गया कोई भी बेंचमार्किंग पूरी तरह से बेकार है। (और यदि आप अनुकूलन को सक्षम करते हैं, तो लूप अनुकूलित हो जाता है। इसलिए आपका बेंचमार्किंग कोड भी त्रुटिपूर्ण है। आपको लूप को चलाने के लिए मजबूर करने की आवश्यकता है, आमतौर पर परिणाम या समान को जोड़कर, और इसे अंत में प्रिंट कर सकते हैं)

ऐसा लगता है कि जो आप माप रहे हैं वह मूल रूप से "कंपाइलर सबसे डीबगिंग ओवरहेड सम्मिलित करता है"। और पता चला कि उत्तर सी है। लेकिन यह हमें नहीं बताता कि कौन सा कार्यक्रम सबसे तेज है। क्योंकि जब आप गति चाहते हैं, तो आप अनुकूलन सक्षम करते हैं।

वैसे, यदि आप भाषाओं को किसी भी अन्य की तुलना में "तेज" होने की धारणा को छोड़ देते हैं, तो आप लंबे समय में खुद को बहुत अधिक सिरदर्द से बचा लेंगे। अंग्रेजी की तुलना में C # में अधिक गति नहीं है।

सी भाषा में कुछ चीजें हैं जो एक भोले नॉन-ऑप्टिमाइज़िंग कंपाइलर में भी कुशल होंगी, और कुछ अन्य हैं जो एक कंपाइलर पर बहुत कुछ निर्भर करती हैं ताकि सब कुछ दूर हो सके। और हां, वही C # या किसी अन्य भाषा के लिए जाता है।

निष्पादन की गति निम्न द्वारा निर्धारित की जाती है:

  • वह प्लेटफ़ॉर्म जो आप चला रहे हैं (OS, हार्डवेयर, सिस्टम पर चलने वाला अन्य सॉफ़्टवेयर)
  • संकलक
  • आपका स्रोत कोड

एक अच्छा C # कंपाइलर कुशल कोड देगा। एक खराब सी कंपाइलर धीमा कोड उत्पन्न करेगा। C # कोड उत्पन्न करने वाले C कंपाइलर के बारे में क्या है, जिसे आप C C # कंपाइलर के माध्यम से चला सकते हैं? कितना तेज चलेगा? भाषा में गति नहीं है। आपका कोड करता है


यहाँ बहुत अधिक दिलचस्प पढ़ने के लिए: blogs.msdn.com/ricom/archive/2005/05/10/416151.aspx
डैनियल

18
अच्छा जवाब है, लेकिन मैं भाषा की गति के बारे में असहमत हूं, कम से कम सादृश्य में: यह पाया गया है कि लंबे स्वरों की उच्च आवृत्ति के कारण वेल्श एक धीमी भाषा है। इसके अतिरिक्त, लोग शब्दों (और शब्द सूचियों) को बेहतर याद रखते हैं यदि वे कहने के लिए तेज़ हों। web.missouri.edu/~cowann/docs/articles/before%201993/… en.wikipedia.org/wiki/Vowel_length en.wikipedia.org/wiki/Welsh_gage
अपवाद

1
क्या यह इस बात पर निर्भर नहीं करता कि आप वेल्श में क्या कह रहे हैं ? मुझे यह संभावना नहीं लगती कि सब कुछ धीमा है।
जल्फ

5
++ हे दोस्तों, यहाँ से दूर मत जाओ। यदि एक ही प्रोग्राम एक भाषा में दूसरे की तुलना में तेज़ी से चलता है, तो यह इसलिए है क्योंकि अलग-अलग असेंबली कोड जेनरेट होता है। इस विशेष उदाहरण में, 99% या अधिक समय चल जाएगा i, और sqrt, इसलिए इसे मापा जा रहा है।
माइक डनलैवी

116

मैं इसे संक्षिप्त रखूंगा, यह पहले से ही उत्तर के रूप में चिह्नित है। C # को एक अच्छी तरह से परिभाषित फ्लोटिंग पॉइंट मॉडल होने का बड़ा फायदा है। यह सिर्फ x86 और x64 प्रोसेसर पर सेट FPU और SSE निर्देश के मूल संचालन मोड से मेल खाने के लिए होता है। वहां कोई संयोग नहीं। JITTER कुछ इनलाइन निर्देशों के लिए Math.Sqrt () का संकलन करता है।

मूल C / C ++ पीछे की संगतता के वर्षों के साथ दुखी है। / Fp: exact, / fp: fast और / fp: सख्त संकलन विकल्प सबसे अधिक दिखाई देते हैं। तदनुसार, यह एक CRT फ़ंक्शन को कॉल करता है जो sqrt () को लागू करता है और परिणाम को समायोजित करने के लिए चयनित फ़्लोटिंग पॉइंट विकल्पों की जाँच करता है। वह धीमा है।


66
यह C ++ प्रोग्रामर्स के बीच एक अजीब सा विश्वास है, उन्हें लगता है कि C # द्वारा उत्पन्न मशीन कोड किसी तरह से एक देशी कंपाइलर द्वारा उत्पन्न मशीन कोड से अलग है। केवल एक ही प्रकार है। कोई फर्क नहीं पड़ता कि आप किस gcc संकलक स्विच का उपयोग करते हैं या इनलाइन असेंबली लिखते हैं, अभी भी केवल एक FSQRT निर्देश है। यह हमेशा तेज नहीं होता है क्योंकि एक देशी भाषा ने इसे उत्पन्न किया है, सीपीयू परवाह नहीं करता है।
हंस पसंत

16
Ngen.exe के साथ यही प्री-जटिंग है। हम C # की बात कर रहे हैं, जावा की नहीं।
हंस पैसेंट

20
@ user877329 - वास्तव में? वाह।
एंड्रास ज़ोल्टन

7
नहीं, x64 घबराना SSE का उपयोग करता है। Math.Sqrt () को sqrtsd मशीन कोड निर्देश में अनुवादित किया जाता है।
हंस पैसिव

6
हालांकि यह तकनीकी रूप से भाषाओं के बीच अंतर नहीं है, लेकिन .net JITter विशिष्ट सी / सी ++ कंपाइलर की तुलना में सीमित अनुकूलन करता है। सबसे बड़ी सीमाओं में से एक सिमडी सपोर्ट की कमी है जो कोड को अक्सर 4x धीमा बनाता है। कई आंतरिक चीजों को उजागर नहीं करना एक बड़ा कारण हो सकता है, लेकिन यह इस बात पर निर्भर करता है कि आप क्या कर रहे हैं।
कोडइन्चोस

57

मैं C ++ और C # डेवलपर हूं। मैंने .NET फ्रेमवर्क के पहले बीटा के बाद से C # एप्लिकेशन विकसित किया है और मुझे C ++ एप्लिकेशन विकसित करने में 20 से अधिक वर्षों का अनुभव है। सबसे पहले, C # कोड कभी भी C ++ एप्लिकेशन की तुलना में तेज़ नहीं होगा, लेकिन मैं प्रबंधित कोड, यह कैसे काम करता है, इंटर-ऑप लेयर, मेमोरी मैनेजमेंट इंटर्नल, डायनेमिक टाइप सिस्टम और कचरा संग्रहकर्ता के बारे में एक लंबी चर्चा से नहीं गुजरेगा। फिर भी, मुझे यह कहते हुए जारी रखना चाहिए कि यहाँ सूचीबद्ध बेंचमार्क सभी परिणाम उत्पन्न करते हैं।

मुझे समझाने दो: पहली चीज जिस पर हमें विचार करने की आवश्यकता है वह है CIT (.NET फ्रेमवर्क 4) के लिए JIT कंपाइलर। अब जेआईटी विभिन्न अनुकूलन एल्गोरिदम का उपयोग करके सीपीयू के लिए मूल कोड का उत्पादन करता है (जो कि डिफ़ॉल्ट सी ++ ऑप्टिमाइज़र की तुलना में अधिक आक्रामक होता है) और विजुअल स्टूडियो द्वारा उपयोग किए जाने वाले निर्देश सेट वास्तविक सीपीयू का एक निकट प्रतिबिंब हैं। मशीन में घड़ी कोड को कम करने और सीपीयू पाइपलाइन कैश में हिट दर में सुधार करने और आगे हाइपर-थ्रेडिंग अनुकूलन जैसे कि हमें निर्देश पुन: व्यवस्थित करने और शाखा भविष्यवाणी से संबंधित सुधारों को उत्पन्न करने के लिए मशीन कोड में कुछ निश्चित प्रतिस्थापन किए जा सकते हैं।

इसका मतलब यह है कि जब तक आप अपने C ++ एप्लिकेशन को RAILASE बिल्ड (DEBUG बिल्ड नहीं) के लिए सही पैरामीटर्स का उपयोग करके संकलित करते हैं, तब तक आपका C ++ एप्लिकेशन संबंधित C # या .NET आधारित एप्लिकेशन की तुलना में अधिक धीरे-धीरे प्रदर्शन कर सकता है। अपने C ++ एप्लिकेशन पर प्रोजेक्ट गुणों को निर्दिष्ट करते समय, सुनिश्चित करें कि आप "पूर्ण अनुकूलन" और "फास्ट कोड के पक्ष" को सक्षम करते हैं। यदि आपके पास 64 बिट मशीन है, तो आप x64 को लक्ष्य प्लेटफ़ॉर्म के रूप में बनाना चाहते हैं, अन्यथा आपका कोड रूपांतरण सब-लेयर (WOW64) के माध्यम से निष्पादित किया जाएगा, जो प्रदर्शन को काफी कम कर देगा।

एक बार जब आप संकलक में सही अनुकूलन करते हैं, तो मुझे C ++ एप्लिकेशन के लिए .72 सेकंड और C # एप्लिकेशन के लिए 1.16 सेकंड (दोनों बिल्ड बिल्ड में) मिलते हैं। चूँकि C # एप्लिकेशन बहुत बुनियादी है और स्टैक पर लूप में उपयोग की जाने वाली मेमोरी को आवंटित करता है और ढेर पर नहीं, यह वास्तव में ऑब्जेक्ट्स, भारी कंप्यूटर्स और बड़े डेटा-सेट्स में शामिल एक वास्तविक एप्लिकेशन की तुलना में बहुत बेहतर प्रदर्शन कर रहा है। इसलिए उपलब्ध कराए गए आंकड़े C # और .NET फ्रेमवर्क के प्रति आशावादी आंकड़े हैं। इस पूर्वाग्रह के साथ भी, C ++ एप्लिकेशन समकक्ष C # एप्लिकेशन की तुलना में आधे से अधिक समय में पूरा होता है। ध्यान रखें कि मैंने जो Microsoft C ++ कंपाइलर का उपयोग किया था, उसमें सही पाइपलाइन और हाइपरथ्रेडिंग ऑप्टिमाइज़ेशन (असेंबली निर्देशों को देखने के लिए WinDBG का उपयोग करना) नहीं था।

अब अगर हम Intel कम्पाइलर का उपयोग करते हैं (जो कि AMD / Intel प्रोसेसर पर उच्च प्रदर्शन अनुप्रयोगों को उत्पन्न करने के लिए एक उद्योग रहस्य है), तो वही कोड Microsoft Visual Studio 2010 का उपयोग करके C ++ निष्पादन योग्य बनाम .72 सेकंड के लिए .54 सेकंड में निष्पादित होता है। तो अंत में, अंतिम परिणाम हैं .54 सेकंड C ++ के लिए और 1.16 सेकंड C # के लिए। तो .NET JIT कंपाइलर द्वारा कोड का उत्पादन C ++ निष्पादन योग्य की तुलना में 214% अधिक समय लेता है। .54 सेकंड में बिताया गया अधिकांश समय सिस्टम से समय प्राप्त करने में था और लूप के भीतर ही नहीं!

आँकड़ों में भी गायब है स्टार्टअप और सफाई समय जो समय में शामिल नहीं हैं। C # एप्लिकेशन C ++ अनुप्रयोगों की तुलना में स्टार्ट-अप और समाप्ति पर बहुत अधिक समय व्यतीत करते हैं। इसके पीछे का कारण जटिल है और .NET रनटाइम कोड सत्यापन दिनचर्या और स्मृति प्रबंधन सबसिस्टम के साथ करना है जो मेमोरी आवंटन और कचरे को अनुकूलित करने के लिए कार्यक्रम की शुरुआत (और परिणामस्वरूप, अंत में) बहुत काम करता है। एकत्र करनेवाला।

C ++ और .NET IL के प्रदर्शन को मापते समय, यह सुनिश्चित करने के लिए विधानसभा कोड को देखना महत्वपूर्ण है कि सभी गणनाएं हैं। मैंने जो पाया वह यह है कि C # में कुछ अतिरिक्त कोड डाले बिना, ऊपर के उदाहरणों में अधिकांश कोड वास्तव में बाइनरी से हटा दिए गए थे। C ++ के साथ भी यही हुआ था जब आपने अधिक आक्रामक अनुकूलक का उपयोग किया था जैसे कि इंटेल C ++ कंपाइलर। मेरे द्वारा ऊपर दिए गए परिणाम 100% सही हैं और विधानसभा स्तर पर मान्य हैं।

इंटरनेट पर बहुत सारे मंचों के साथ मुख्य समस्या यह है कि बहुत से नौसिखिया बिना प्रौद्योगिकी को समझे Microsoft विपणन प्रचार को सुनते हैं और झूठे दावे करते हैं कि C # C ++ से तेज है। दावा है कि सिद्धांत रूप में, C # C ++ से तेज है क्योंकि JIT कंपाइलर CPU के लिए कोड को ऑप्टिमाइज़ कर सकता है। इस सिद्धांत के साथ समस्या यह है कि .NET फ्रेमवर्क में बहुत सी पाइपलाइन मौजूद है जो प्रदर्शन को धीमा कर देती है; प्लंबिंग जो C ++ एप्लिकेशन में मौजूद नहीं है। इसके अलावा, एक अनुभवी डेवलपर को दिए गए प्लेटफॉर्म के लिए उपयोग करने के लिए सही कंपाइलर पता होगा और एप्लिकेशन को संकलित करते समय उपयुक्त झंडे का उपयोग करना होगा। लिनक्स या ओपन सोर्स प्लेटफॉर्म पर, यह एक समस्या नहीं है क्योंकि आप अपने स्रोत को वितरित कर सकते हैं और इंस्टॉलेशन स्क्रिप्ट बना सकते हैं जो उपयुक्त अनुकूलन का उपयोग करके कोड को संकलित करते हैं। खिड़कियों या बंद स्रोत प्लेटफॉर्म पर, आपको विशिष्ट निष्पादन के साथ प्रत्येक को कई निष्पादन योग्य वितरित करना होगा। जिन विंडो बायनेरिज़ को तैनात किया जाएगा वे एमएसआई इंस्टॉलर (कस्टम क्रियाओं का उपयोग करके) द्वारा पता लगाए गए सीपीयू पर आधारित हैं।


22
1. Microsoft ने कभी भी C # के बारे में उन दावों के बारे में नहीं बताया, जिनके दावे तेजी से होने के कारण इसकी लगभग 90% गति, तेजी से विकसित होने (और इसलिए धुन करने के लिए अधिक समय) और स्मृति और प्रकार की सुरक्षा के कारण अधिक बग मुक्त है। जिनमें से सभी सही हैं (मेरे पास 20 साल C ++ में और 10 C # में हैं) 2. स्टार्टअप का प्रदर्शन ज्यादातर मामलों में अर्थहीन है। 3. वहाँ भी तेजी से कर रहे हैं C # LLVM की तरह संकलक (इसलिए इंटेल बाहर लाने के लिए सेब के लिए सेब नहीं है)
बेन

13
स्टार्टअप का प्रदर्शन निरर्थक नहीं है। अधिकांश एंटरप्राइज़ वेब आधारित एप्लिकेशन में यह बहुत महत्वपूर्ण है, यही कारण है कि Microsoft ने .NET 4.0 में प्री-लोड किए जाने वाले (ऑटोस्टार्ट) होने के लिए वेब पेज पेश किए। जब एप्लिकेशन पूल को हर बार एक बार पुनर्नवीनीकरण किया जाता है, तो पहली बार प्रत्येक पृष्ठ लोड जटिल पृष्ठों के लिए एक महत्वपूर्ण देरी जोड़ देगा और ब्राउज़र पर समय-आउट का कारण बनेगा।
रिचर्ड

8
Microsoft ने पूर्व विपणन सामग्री में .NET के प्रदर्शन के तेज होने के दावे किए। उन्होंने यह भी दावा किया कि कचरा संग्रहकर्ता के प्रदर्शन पर बहुत कम या कोई प्रभाव नहीं पड़ा है। इनमें से कुछ दावों ने इसे अपने पहले संस्करणों में विभिन्न पुस्तकों (ASP.NET और .NET पर) में बनाया। हालाँकि Microsoft विशेष रूप से यह नहीं कहता है कि आपका C # एप्लिकेशन आपके C ++ एप्लिकेशन से अधिक तेज़ होगा, वे "जस्ट-इन-टाइम मीन्स रन-इट-फास्ट" ( msdn.microsoft.com/) जैसे सामान्य टिप्पणियां और मार्केटिंग नारे लगा सकते हैं। en-us / पुस्तकालय / ms973894.aspx )।
रिचर्ड

71
-1, यह शेख़ी गलत और भ्रामक बयानों से भरा है जैसे कि स्पष्ट व्हॉपर "C # कोड कभी भी C ++ एप्लिकेशन से अधिक तेज़ नहीं होगा"
BCoates

32
-1। आपको रिको मारियानी बनाम रेमंड चेन की सी # बनाम सी प्रदर्शन लड़ाई: ब्लॉगs.msdn.com/b/ricom/archive/2005/05/16/418051.aspx को पढ़ना चाहिए । संक्षेप में: यह माइक्रोसॉफ्ट के सबसे चतुर लोगों में से एक था, जो सी वर्जन को सरल सी # वर्जन की तुलना में तेज बनाने के लिए काफी अनुकूलन करता था।
रॉल्फ बज़्ने क्युरिंग

10

मेरा पहला अनुमान एक संकलक अनुकूलन है क्योंकि आप कभी भी रूट का उपयोग नहीं करते हैं। आप बस इसे असाइन करते हैं, फिर इसे बार-बार लिखते हैं।

संपादित करें: लानत है, 9 सेकंड से हराया!


2
मैं कहता हूं आप सही हैं। वास्तविक चर ओवरराइट किया गया है और कभी भी उससे परे उपयोग नहीं किया गया है। Csc सबसे अधिक संभावना है कि पूरे लूप को भुना दे, जबकि c ++ कंपाइलर ने शायद इसे छोड़ दिया था। परिणामों को संचित करने के लिए एक अधिक सटीक परीक्षण होगा और फिर उस परिणाम को अंत में प्रिंट करें। इसके अलावा किसी को बीज के मूल्य को हार्ड कोड नहीं करना चाहिए, बल्कि इसे उपयोगकर्ता-परिभाषित होने के लिए छोड़ देना चाहिए। यह सी # कंपाइलर को सामान छोड़ने के लिए कोई जगह नहीं देगा।

7

यह देखने के लिए कि क्या लूप को अनुकूलित किया जा रहा है, अपने कोड को बदलने का प्रयास करें

root += Math.Sqrt(i);

ans इसी तरह सी कोड में, और फिर लूप के बाहर रूट का मान प्रिंट करें।


6

हो सकता है कि ग # संकलक आपको सूचित कर रहा हो कि आप कहीं भी रूट का उपयोग न करें, इसलिए यह लूप के लिए पूरी तरह से छोड़ देता है। :)

यह मामला नहीं हो सकता है, लेकिन मुझे संदेह है कि कारण जो भी हो, यह संकलक कार्यान्वयन पर निर्भर है। ऑप्टिमाइज़ेशन और रिलीज़ मोड के साथ Microsoft प्रोग्रामर (cl.exe, win32 sdk के भाग के रूप में उपलब्ध) के साथ C प्रोग्राम को संकलित करने का प्रयास करें। मुझे यकीन है कि आप अन्य संकलक पर एक पूर्ण सुधार देखेंगे।

संपादित करें: मुझे नहीं लगता कि संकलक सिर्फ लूप के लिए अनुकूलन कर सकता है, क्योंकि यह जानना होगा कि Math.Sqrt () का कोई दुष्प्रभाव नहीं है।


2
शायद यह वह जानता है।

2
@ नील, @ जेफ: सहमत हैं, यह बहुत आसानी से पता चल सकता है। कार्यान्वयन के आधार पर, Math.Sqrt () पर स्थैतिक विश्लेषण शायद उतना कठिन नहीं होगा, हालांकि मुझे यकीन नहीं है कि विशेष रूप से अनुकूलन क्या किया जाता है।
जॉन फेमिनाला

5

समय चाहे जो भी हो। हो सकता है, कि "बीता हुआ समय" अमान्य है। यह केवल एक वैध होगा यदि आप गारंटी दे सकते हैं कि दोनों कार्यक्रम सटीक समान शर्तों के तहत चलते हैं।

शायद आपको जीत का प्रयास करना चाहिए। $ / usr / bin / time my_cprog; / usr / bin / time my_csprog के बराबर


1
यह क्यों ठुकराया गया है? क्या कोई यह मान रहा है कि व्यवधान और संदर्भ स्विच प्रदर्शन को प्रभावित नहीं करते हैं? क्या कोई टीएलबी मिस, पेज स्वैपिंग आदि पर धारणा बना सकता है?
टॉम

5

मैंने आपके (आपके कोड के आधार पर) 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 पर खींचने की अनुमति नहीं दी जानी चाहिए) हालांकि यह सरणी काफी छोटा है (अत्यधिक मेमोरी का उपयोग नहीं करना चाहता)। मैंने इन्हें रिलीज़ कॉन्फ़िगर में संकलित किया और इन्हें कंसोल विंडो (वीएस के माध्यम से शुरू करने के बजाय) के अंदर से चलाया।

मेरे कंप्यूटर पर C # प्रोग्राम 6.2 और 6.9 सेकंड के बीच बदलता रहता है, जबकि C संस्करण 6.9 और 7.1 के बीच बदलता रहता है।


5

यदि आप विधानसभा स्तर पर कोड को केवल एकल-चरण करते हैं, जिसमें स्क्वायर-रूट रूटीन के माध्यम से कदम शामिल हैं, तो आपको संभवतः आपके प्रश्न का उत्तर मिलेगा।

शिक्षित अनुमान के लिए कोई ज़रूरत नहीं है।


मैं यह जानना चाहता हूं कि यह कैसे करना है
जोश स्टोडोला

आपके आईडीई या डिबगर पर निर्भर करता है। पीजीएम की शुरुआत में ब्रेक। Disassembly विंडो प्रदर्शित करें, और सिंगल-स्टेपिंग शुरू करें। यदि GDB का उपयोग कर रहे हैं, तो एक समय में एक निर्देश को आगे बढ़ाने के आदेश हैं।
माइक डनलैवी

अब यह एक अच्छा सुझाव है, इससे व्यक्ति को यह समझने में मदद मिलती है कि वास्तव में वहां क्या चल रहा है। क्या यह जेएलटी अनुकूलन जैसे कि इनलाइनिंग और टेल कॉल भी दिखाता है?
gjvdkamp

FYI करें: मेरे लिए इसने VC ++ को fadd और fsqrt का उपयोग करते हुए दिखाया जबकि C # ने cvtsi2sd और sqrtsd का उपयोग किया, जो कि मैं समझता हूं कि SSE2 निर्देश हैं और इसलिए बहुत तेजी से जहां समर्थित हैं।
दानियो १०'१२

2

दूसरा कारक जो यहां एक मुद्दा हो सकता है वह यह है कि सी कंपाइलर आपके द्वारा लक्षित प्रोसेसर परिवार के लिए जेनेरिक नेटिव कोड को संकलित करता है, जबकि जब आपने C # कोड संकलित किया तो MSIL उत्पन्न हुआ, तब JIT ने उस सटीक प्रोसेसर को लक्षित करने के लिए संकलित किया है जो आपने किसी भी पूर्ण प्रोसेसर को पूरा करने के लिए संकलित किया है अनुकूलन जो संभव हो सकता है। इसलिए C # से उत्पन्न देशी कोड C की तुलना में काफी तेज हो सकता है।


सिद्धांत रूप में, हाँ। व्यवहार में, यह वास्तव में एक औसत दर्जे का अंतर नहीं करता है। एक या दो प्रतिशत, शायद, यदि आप भाग्यशाली हैं।
जलफ

या - यदि आपके पास कुछ विशेष प्रकार का कोड है जो एक्सटेंशन का उपयोग करता है जो 'जेनेरिक' प्रोसेसर के लिए अनुमत सूची में नहीं हैं। SSE फ्लेवर जैसी चीजें। प्रोसेसर लक्ष्य के साथ उच्च सेट करने का प्रयास करें, यह देखने के लिए कि आपको क्या अंतर मिलता है।
gbjbaanb

1

यह मुझे प्रतीत होगा कि यह स्वयं भाषाओं से कोई लेना-देना नहीं है, बल्कि यह वर्गमूल समारोह के विभिन्न कार्यान्वयनों के साथ करना है।


मुझे अत्यधिक संदेह है कि sqrt कार्यान्वयन में भिन्नता होगी।
एलेक्स फोर्ट

खासकर तब से, यहां तक ​​कि C # में भी, अधिकांश गणित कार्यों को अभी भी प्रदर्शन महत्वपूर्ण माना जाता है और इस तरह से लागू किया जाता है।
मैथ्यू ओलेनिक

fsqrt एक IA-32 प्रोसेसर निर्देश है, इसलिए इन दिनों भाषा कार्यान्वयन अप्रासंगिक है।
श्योर

एक डिबगर के साथ MSVC के sqrt फ़ंक्शन में कदम रखें। यह केवल fsqrt निर्देश को निष्पादित करने की तुलना में बहुत अधिक कर रहा है।
bk1e

1

दरअसल दोस्तों, लूप को अनुकूलित नहीं किया जा रहा है। मैंने जॉन का कोड संकलित किया और परिणाम की जांच की। 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

जब तक कि रनटाइम इतना स्मार्ट न हो जाए कि लूप को कुछ भी महसूस न हो और उसे छोड़ दिया जाए?

संपादित करें: सी # को बदलना:

 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 मिलियन अतिरिक्त ऑपरेटरों को जोड़ने का ओवरहेड है?


3
आईएल को देखते हुए आप अनुकूलन के बारे में बहुत कुछ नहीं बताते हैं क्योंकि यद्यपि सी # संकलक कुछ चीजों को निरंतर तह और मृत कोड को हटाने की तरह करता है, आईएल फिर भार उठाता है और बाकी को लोड समय पर करता है।
डैनियल इयरविकर

यही मैंने सोचा कि मामला हो सकता है। यहां तक ​​कि यह काम करने के लिए मजबूर करता है, हालांकि, यह अभी भी सी संस्करण की तुलना में 9 सेकंड तेज है। (मुझे उम्मीद नहीं होगी कि)
दाना
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.