मेरे पास इस प्रश्न के लिए एक त्वरित जांच थी, लेकिन मुझे कोई जवाब नहीं मिला - हालांकि मुझे लगता है कि इसे पहले यहां लाया जा सकता था।

मैं c++ में इरेटोस्थनीज की चलनी का एक सरल कार्यान्वयन लिखने और परिणाम के समय के बारे में गड़बड़ कर रहा था:

#include <iostream> 
#include <math.h>


int main() {

  int n = 100000;
  int seive [n];

  for (int i=0; i<n; i++) {
    seive[i] = i;
  }

  for (int i=2; i < ceil(sqrt(n)); i++) {
    for (int j=i*2; j<=n; j+=i) {
      seive[j-1] = -9;
    }
  }

  for (int i=0; i<n; i++) {
    if (seive[i] != -9) {
      std::cout << i+1 << "\n";
    }
  }

  return 0;
}

मैं इसका उपयोग करके संकलित करता हूं:

g++ seive.cpp -o seiveCpp

और फिर इसका उपयोग करने का समय:

time ./seiveCpp

पहली बार:

./seiveCpp  0.01s user 0.01s system 10% cpu 0.184 total

दूसरी बार:

./seiveCpp  0.01s user 0.01s system 58% cpu 0.034 total

तीसरी बार:

./seiveCpp  0.01s user 0.01s system 59% cpu 0.037 total

आदि।

अगर मैं इसे कई बार दोहराता हूं, तो ऐसा लगता है कि कोड चलाना हमेशा लगभग 5x धीमा होता है, जो लगातार सभी समय की तुलना में पहली बार धीमा होता है।

ऐसा होने के पीछे क्या कारण है?

मैं इसे 2017 मैकबुक प्रो, 2.3 गीगाहर्ट्ज़ डुअल-कोर इंटेल कोर i5 पर चला रहा हूं, और ऐप्पल क्लैंग संस्करण 11.0.0 (क्लैंग -1100.0.33.12) के साथ संकलित कर रहा हूं।

1
user438383 28 मार्च 2020, 23:57
1
int seive [n]; -- यह C++ नहीं है। C++ में Arrays के आकार एक संकलन-समय अभिव्यक्ति द्वारा दर्शाए जाने चाहिए, न कि रनटाइम चर या अभिव्यक्ति जैसे n। इसके बजाय std::vector<int> seive(n); का प्रयोग करें।
 – 
PaulMcKenzie
29 मार्च 2020, 00:11
यदि आप अपने प्रोग्राम को बेंचमार्क कर रहे हैं तो ऑप्टिमाइज़ेशन चालू करना एक अच्छा विचार होगा। -O2 या -O3 विकल्प फ़्लैग जोड़ने का प्रयास करें।
 – 
Bob__
29 मार्च 2020, 00:37
प्रदर्शन (चलनी का) मापने का आपका तंत्र अनुपयुक्त है। सबसे बड़ा प्रभाव यह है कि आपके समय में स्पष्ट रूप से सभी प्राइम के कोउट की लागत शामिल है। एक कंसोल के लिए cout बहुत महंगा है। आप आउटपुट को किसी फ़ाइल में रीडायरेक्ट कर सकते हैं। आप परिणाम को स्मृति में सहेज सकते हैं (शायद स्ट्रिंगस्ट्रीम?), फिर टाइमर बंद होने के बाद इसे cout करें।
 – 
2785528
29 मार्च 2020, 00:38
असल में मैं कोड के इस विशिष्ट टुकड़े के प्रदर्शन के बारे में बहुत परेशान नहीं हूं - मैं बस समय के साथ हुआ और ध्यान दिया कि यह दूसरी बार धीमी गति से चल रहा था। यह इस उदाहरण द्वारा सचित्र एक सामान्य प्रश्न था।
 – 
user438383
29 मार्च 2020, 00:40
शायद आपने कुछ नहीं सीखा है क्योंकि एक टर्मिनल के लिए cout बेतहाशा परिवर्तनशील है और आमतौर पर धीमा है। शायद आप बहुत अधिक भरोसा करते हैं, 'समय' उपयोगिता के उपयोग पर बहुत अधिक विश्वास करते हैं।
 – 
2785528
29 मार्च 2020, 00:43

3 जवाब

सबसे बढ़िया उत्तर

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

इसलिए निष्पादन समय से कुछ एल्गोरिदम की तुलना करने के लिए, सौ बार चलाना और सबसे छोटा समय लेना अच्छा अभ्यास है।

3
Midren 29 मार्च 2020, 00:02

बहुत बड़े अंतर को देखते हुए, मुझे लगता है कि जब आप पहला रन शुरू करते हैं तो सीपीयू कम प्रदर्शन मोड में होता है, लेकिन फिर पहले रन से लोड के तहत ओएस इसे उच्च प्रदर्शन मोड में बदल देता है, जिसे आप कम निष्पादन समय के रूप में देखते हैं। .

सुनिश्चित करें कि आपकी नोटबुक एसी पावर से जुड़ी है और यदि आप प्रभाव से बचना चाहते हैं तो सभी बिजली-बचत विकल्प अक्षम हैं।

किसी भी स्थिति में अभी भी कैशिंग प्रभाव शेष रहेगा (उदाहरण के लिए निष्पादन योग्य सामग्री को स्मृति में कैश किया जा सकता है)। लेकिन ये 100ms के क्रम में नहीं होना चाहिए, मुझे लगता है।

सामान्य तौर पर जब आप बेंचमार्क कोड करते हैं, तो आपको हमेशा एक वार्मअप रन करना चाहिए, क्योंकि किसी न किसी कारण से कुछ हद तक ऐसे प्रभाव हमेशा होंगे। आप आम तौर पर वास्तविक परीक्षण रन करना चाहते हैं जब पर्यावरण संतुलन की स्थिति में पहुंच गया है, इसलिए बोलने के लिए।

2
walnut 29 मार्च 2020, 00:27

एक प्रोग्राम को कई बार चलाते समय पहली बार OS को फ़ाइल को मेमोरी में लोड करना पड़ता है, अगली बार इसके पहले से मौजूद होने की संभावना है (हालाँकि कंपाइलर/लिंकर सेटिंग्स के आधार पर स्थानांतरण अभी भी आवश्यक हो सकता है, अर्थात् स्थिति-स्वतंत्र-कोड उत्पन्न होता है)। यदि आप एक ही प्रक्रिया में एक ही कोड को कई बार चला रहे हैं तो शाखा स्थान का उत्तर लागू होने की अधिक संभावना होगी (जो प्रदर्शन डेटा एकत्र करते समय एक अच्छा विचार है - अपने प्रोग्राम में टाइमिंग कोड डालें और ब्याज के कोड को कई बार चलाएं , अपने पूरे प्रोग्राम को कई बार चलाने और बाहरी समय प्रोग्राम का उपयोग करने के बजाय प्रत्येक लूप को समय देना)।

1
SoronelHaetir 29 मार्च 2020, 00:20