C ++ प्रोग्राम्स में scanf () का उपयोग करना, सिने का उपयोग करने से अधिक तेज़ है?


126

मुझे नहीं पता कि क्या यह सच है, लेकिन जब मैं साइटों को प्रदान करने वाली समस्या में से एक पर अक्सर पूछे जाने वाले प्रश्न पढ़ रहा था, तो मुझे कुछ मिला, जिसने मेरा दृष्टिकोण बढ़ा दिया

अपने इनपुट / आउटपुट विधियों की जाँच करें। C ++ में, Cin और cout का उपयोग करना बहुत धीमा है। इनका उपयोग करें, और आप गारंटी देंगे कि किसी भी समस्या को इनपुट या आउटपुट की सभ्य मात्रा में हल करने में सक्षम नहीं हैं। इसके बजाय प्रिंटफ और स्कैनफ का उपयोग करें।

क्या कोई इसे स्पष्ट कर सकता है? वास्तव में उपयोग कर रहा है scanf () तेजी से उपयोग करने की तुलना सी ++ प्रोग्राम में CIN >> कुछ ? यदि हाँ, तो क्या यह C ++ प्रोग्राम में उपयोग करने के लिए एक अच्छा अभ्यास है? मैंने सोचा था कि यह सी विशिष्ट था, हालांकि मैं सिर्फ सी ++ सीख रहा हूं ...


14
मेरा अनुमान है: खराब प्रोग्रामर खराब प्रदर्शन के लिए मानक पुस्तकालयों को दोष देता है। हमेशा की तरह विनोदी "मुझे लगता है कि मुझे जीसीसी में एक बग मिला" रोना।
जॉन कुगेलमैन

11
@eclipse: प्रतियोगिताओं के लिए मैंने जिन ACM समस्याओं पर काम किया है, उनमें पर्याप्त मात्रा में इनपुट / आउटपुट होते हैं और आपके प्रोग्राम को 60 सेकंड से कम के प्रश्नों को हल करना पड़ता है ... यह यहाँ एक वास्तविक मुद्दा बन जाता है।
मपेन

19
--- उस ने कहा, अगर आपको उस अतिरिक्त प्रदर्शन को बढ़ावा देने के लिए स्कैनफ () पर भरोसा करने की आवश्यकता है, तो आप समस्या के बारे में गलत तरीके से जा रहे हैं :)
एमपीएन

4
अवलोकन के रूप में - मैंने इसके साथ खेला, और दूसरी समस्याओं (PRIME1) पर - एक ही एल्गोरिथ्म का उपयोग करते हुए, दोनों बार, एक बार Cin / cout का उपयोग करने के बाद और एक बार scanf / printf के साथ और पहला संस्करण दूसरे की तुलना में तेज़ था (लेकिन पास पर्याप्त है कि यह सांख्यिकीय अप्रासंगिक है)। यह उन समस्याओं में से एक है जिन्हें इनपुट / आउटपुट गहन होने के रूप में चिह्नित किया गया है, और इनपुट / आउटपुट की विधि ने कोई सांख्यिकीय अंतर नहीं बनाया है।
ग्रहण

4
@ ग्रहण - दोनों विधियों के परीक्षण के बारे में जानकारी के लिए धन्यवाद। हालांकि मैं दुखी हूँ - मैंने सिनेमा और
कॉट

जवाबों:


209

यहां एक साधारण मामले का त्वरित परीक्षण है: सभी संख्याओं के मानक इनपुट और XOR से संख्याओं की एक सूची पढ़ने के लिए एक कार्यक्रम।

आईस्ट्रीम संस्करण:

#include <iostream>

int main(int argc, char **argv) {

  int parity = 0;
  int x;

  while (std::cin >> x)
    parity ^= x;
  std::cout << parity << std::endl;

  return 0;
}

स्कैनफ़ संस्करण:

#include <stdio.h>

int main(int argc, char **argv) {

  int parity = 0;
  int x;

  while (1 == scanf("%d", &x))
    parity ^= x;
  printf("%d\n", parity);

  return 0;
}

परिणाम

एक तीसरे कार्यक्रम का उपयोग करते हुए, मैंने एक पाठ फ़ाइल बनाई जिसमें 33,280,276 यादृच्छिक संख्याएँ थीं। निष्पादन समय हैं:

iostream version:  24.3 seconds
scanf version:      6.4 seconds

कंपाइलर की ऑप्टिमाइज़ेशन सेटिंग्स को बदलने से परिणाम बिल्कुल नहीं बदले।

इस प्रकार: वास्तव में एक गति अंतर है।


EDIT: उपयोगकर्ता clyfish नीचे इंगित करता है कि गति अंतर काफी हद तक iostream I / O फ़ंक्शन के साथ CI / O फ़ंक्शन के साथ सिंक्रनाइज़ेशन बनाए रखने के कारण है। हम इसे कॉल के साथ बंद कर सकते हैं std::ios::sync_with_stdio(false);:

#include <iostream>

int main(int argc, char **argv) {

  int parity = 0;
  int x;

  std::ios::sync_with_stdio(false);

  while (std::cin >> x)
    parity ^= x;
  std::cout << parity << std::endl;

  return 0;
}

नए परिणाम:

iostream version:                       21.9 seconds
scanf version:                           6.8 seconds
iostream with sync_with_stdio(false):    5.5 seconds

सी ++ iostream जीत! यह पता चला है कि यह आंतरिक सिंकिंग / फ्लशिंग क्या है जो आमतौर पर iostream i / o को धीमा कर देता है। यदि हम stdio और iostream नहीं मिला रहे हैं, तो हम इसे बंद कर सकते हैं, और फिर iostream सबसे तेज़ है।

कोड: https://gist.github.com/3845568


6
मुझे लगता है कि 'एंडल' का उपयोग निष्पादन को धीमा कर सकता है।
कृष्ण मोहन

2
Std :: endl का उपयोग लूप में नहीं है।
निबोट

पर या बंद सिंक के साथ कोई फर्क नहीं पड़ता। इसके लिए libc ++ को दोष दें। यह केवल libstdc ++
iBug

क्या आपको लगता है कि <cstdio> और <stdio.h> के बीच कोई अंतर होगा?
चंद्रहास अरोड़ी

iostreamजब आप एक scanfकॉल में एक से अधिक पूर्णांक पार्स करते हैं तो खो देता है ।
मैक्सिम Egorushkin

68

http://www.quora.com/Is-cin-cout-slower-than-scanf-printf/answer/Aditya-Vishwakarma

cin/ का प्रदर्शन coutधीमा हो सकता है क्योंकि उन्हें अंतर्निहित सी लाइब्रेरी के साथ खुद को सिंक में रखने की आवश्यकता होती है। यह आवश्यक है अगर C IO और C ++ IO दोनों का उपयोग किया जा रहा है।

हालाँकि, यदि आप केवल C ++ IO का उपयोग करने जा रहे हैं, तो किसी भी IO परिचालनों से पहले नीचे की पंक्ति का उपयोग करें।

std::ios::sync_with_stdio(false);

इस पर अधिक जानकारी के लिए, संबंधित libstdc ++ डॉक्स को देखें


बस ऊपर की रेखा (std :: ios :: Sync_with_stdio (झूठी);) की जाँच की है और यह वास्तव में istream को लगभग cstdio
gabrielhidasy

Cin.tie (static_cast <ostream *> (0)) का भी उपयोग करें; बेहतर प्रदर्शन के लिए
मोहम्मद अल-नकीब

42

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

वहाँ एक बहुत ही स्वादिष्ट हर्ब Sutter "द्वारा यहाँ लिखा लेख है मनोर खेत की स्ट्रिंग formatters " जो की तरह स्ट्रिंग formatters के प्रदर्शन के विस्तार का एक बहुत में चला जाता है sscanfऔर lexical_castऔर क्या बातें की तरह बना रहे थे उन्हें धीरे-धीरे या तेजी से चलाने के। यह एक तरह का सादृश्य है, शायद इस तरह की चीजें जो C शैली IO और C ++ शैली के बीच प्रदर्शन को प्रभावित करती हैं। फ़ॉर्मेटर्स के साथ मुख्य अंतर प्रकार की सुरक्षा और स्मृति आवंटन की संख्या के रूप में है।


19

मैंने युवी ऑनलाइन पर एक समस्या पर काम करने वाली एक शाम बिताई (फैक्टोवाइज़र, एक बहुत ही दिलचस्प समस्या, इसे देखें):

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=35&page=show_problem&problem=1080

मुझे अपने सबमिशन पर TLE (समय सीमा पार हो गई) हो रही थी। ऑनलाइन जज साइटों को हल करने वाली इन समस्या पर, आपके पास अपने समाधान का मूल्यांकन करने के लिए उपयोग किए जाने वाले हजारों परीक्षण मामलों को संभालने के लिए 2-3 सेकंड की समय सीमा होती है। इस तरह की कम्प्यूटेशनल रूप से गहन समस्याओं के लिए, प्रत्येक माइक्रोसेकंड मायने रखता है।

मैं सुझाए गए एल्गोरिथ्म का उपयोग कर रहा था (साइट के लिए चर्चा मंचों में पढ़ें), लेकिन अभी भी टीएलई हो रहा था।

मैंने सिर्फ "Cin >> n >> m" को "scanf ("% d% d ", & n, & m)" और कुछ छोटे "couts" को "printfs" में बदल दिया, और मेरा TLE "स्वीकृत" "हो गया!

तो, हाँ, यह एक बड़ा बदलाव ला सकता है, खासकर जब समय सीमा कम हो।


इस बात से सहमत। यूएवी
मोहम्मद एल-

6

यदि आप प्रदर्शन और स्ट्रिंग प्रारूपण दोनों की परवाह करते हैं, तो मैथ्यू विल्सन की फास्टफ़ॉर्मैट लाइब्रेरी पर एक नज़र डालें ।

संपादित करें - उस पुस्तकालय पर accu प्रकाशन के लिए लिंक: http://accu.org/index.php/journals/1539


पूरी तरह से सहमत हूँ। लेकिन आपको इस बात से अवगत होना चाहिए कि FastFormat केवल आउटपुट के लिए है। इसमें कोई इनपुट / रीड सुविधाएं नहीं हैं। (अभी नहीं, वैसे भी)
dcw

दुर्भाग्य से वह लिंक मृत प्रतीत होता है। यहां एक
वेकबैक

2

वहाँ stdio कार्यान्वयन ( libio ) हैं जो File * को C ++ स्ट्रीमबफ के रूप में लागू करते हैं, और रनटाइम प्रारूप पार्सर के रूप में fprintf हैं। IOstreams को रनटाइम प्रारूप पार्सिंग की आवश्यकता नहीं है, यह सब संकलन समय पर किया जाता है। इसलिए, साझा किए गए बैकएंड के साथ, यह उम्मीद करना उचित है कि iostreams रनटाइम में तेज है।


मुझे ऐसा नहीं लगता। मुझे लगता है कि जीएनयू का परिवाद शुद्ध सी और विधानसभा है।
क्रिस लुत्ज

2

हाँ iostream cstdio की तुलना में धीमी है।
यदि आप C ++ में विकास कर रहे हैं तो हाँ, आपको शायद cstdio का उपयोग नहीं करना चाहिए।
अगर आपने फॉर्मेटिंग, टाइप सेफ्टी, ब्लाह, ब्लाह, ब्लाह के बारे में परवाह नहीं की है, तो स्कैन / आई से ओ पाने के और भी तेज़ तरीके हैं।

उदाहरण के लिए यह STDIN से नंबर पाने के लिए एक नियमित दिनचर्या है:

inline int get_number()
{
    int c;        
    int n = 0;

    while ((c = getchar_unlocked()) >= '0' && c <= '9')
    {
        // n = 10 * n + (c - '0');
        n = (n << 3) + ( n << 1 ) + c - '0';
    }
    return n;
}

1
getchar_unlocked () गैर-मानक है, और gcc नहीं दृश्य स्टूडियो के लिए उपलब्ध है
मोहम्मद अल-नकिब

1

समस्या यह है कि cinइसमें बहुत अधिक ओवरहेड शामिल है क्योंकि यह आपको scanf()कॉल के ऊपर एक अमूर्त परत देता है । आप उपयोग नहीं करना चाहिए scanf()से अधिक cinहै, तो आप सी ++ सॉफ्टवेयर लिख रहे हैं, क्योंकि वह चाहते है cinके लिए है। यदि आप प्रदर्शन चाहते हैं, तो आप शायद वैसे भी C ++ में I / O नहीं लिखेंगे।


2
क्या cinवास्तव में "अमूर्त" (रनटाइम पर) की तुलना में अधिक है scanf? मुझे ऐसा नहीं लगता ... scanfरनटाइम में प्रारूप स्ट्रिंग की व्याख्या करनी चाहिए, जबकि iostreamसंकलन-समय पर प्रारूप को जानता है।
निबोट

1
@nibot: प्रकार संकलन-समय पर जाना जाता है, लेकिन प्रारूप में नहीं । इनपुट के हेक्साडेसिमल होने की उम्मीद है या नहीं उदाहरण के लिए पूरी तरह से इस std::istreamबात पर निर्भर करता है कि रनटाइम पर कैसे कॉन्फ़िगर किया गया है (I / O जोड़तोड़ के माध्यम से या istreamऑब्जेक्ट पर स्वयं झंडे सेट करके )। FILE*दूसरी ओर एक वस्तु में ऐसी कोई स्थिति नहीं होती है, इसलिए scanfइस संबंध में एक कॉल अधिक स्थिर है।
dreamlax

1

बयानों cinऔर coutसामान्य उपयोग में की तुलना में धीमी होने लगते हैं scanfऔर printfC ++, लेकिन वास्तव में वे तेजी से कर रहे हैं!

बात यह है: सी ++ में, जब भी आप उपयोग करते हैं cinऔर cout, एक सिंक्रनाइज़ेशन प्रक्रिया डिफ़ॉल्ट रूप से होती है जो यह सुनिश्चित करती है कि यदि आप दोनों scanfऔर cinअपने कार्यक्रम में उपयोग करते हैं, तो वे दोनों एक-दूसरे के साथ काम करते हैं। इस सिंक प्रक्रिया में समय लगता है। इसलिए cinऔर coutAPPEAR धीमा होना चाहिए।

हालाँकि, यदि सिंक्रनाइज़ेशन प्रक्रिया नहीं होने के लिए सेट है, cinसे अधिक तेज़ है scanf

समन्वयन प्रक्रिया को छोड़ने के लिए, अपने प्रोग्राम में निम्नलिखित कोड स्निपेट को शुरू में शामिल करें main():

std::ios::sync_with_stdio(false);

अधिक जानकारी के लिए इस साइट पर जाएँ ।


सिंक्रनाइज़ेशन के बारे में आपके स्पष्टीकरण के लिए +1। मैंने बस सिंक को बंद कर दिया था और कुछ कोड में स्कैनफ़ और सिन दोनों का इस्तेमाल किया था । अब मुझे पता है कि इसमें क्या गलत था। धन्यवाद!
४५

1
#include <stdio.h>
#include <unistd.h>

#define likely(x)       __builtin_expect(!!(x), 1)
#define unlikely(x)     __builtin_expect(!!(x), 0)

static int scanuint(unsigned int* x)
{
  char c;
  *x = 0;

  do
  {
      c = getchar_unlocked();
      if (unlikely(c==EOF)) return 1;
  } while(c<'0' || c>'9');

  do
  {
      //*x = (*x<<3)+(*x<<1) + c - '0';
      *x = 10 * (*x) + c - '0';
      c = getchar_unlocked();
      if (unlikely(c==EOF)) return 1;
  } while ((c>='0' && c<='9'));

  return 0;
}

int main(int argc, char **argv) {

  int parity = 0;
  unsigned int x;

  while (1 != (scanuint(&x))) {
    parity ^= x;
  }
  parity ^=x;
  printf("%d\n", parity);

  return 0;
}

फ़ाइल के अंत में एक बग है, लेकिन यह सी कोड नाटकीय रूप से तेज सी ++ संस्करण की तुलना में तेज है।

paradox@scorpion 3845568-78602a3f95902f3f3ac63b6beecaa9719e28a6d6  make test        
time ./xor-c < rand.txt
360589110

real    0m11,336s
user    0m11,157s
sys 0m0,179s
time ./xor2-c < rand.txt
360589110

real    0m2,104s
user    0m1,959s
sys 0m0,144s
time ./xor-cpp < rand.txt
360589110

real    0m29,948s
user    0m29,809s
sys 0m0,140s
time ./xor-cpp-noflush < rand.txt
360589110

real    0m7,604s
user    0m7,480s
sys 0m0,123s

मूल C ++ ने 30sec लिया C कोड 2sec लिया।


-1

बेशक, आईस्ट्रीम पर cstdio का उपयोग करना हास्यास्पद है। कम से कम जब आप सॉफ़्टवेयर विकसित करते हैं (यदि आप पहले से ही c ++ ओवर सी का उपयोग कर रहे हैं, तो सभी तरह से जाएं और इसका नुकसान होने के बजाय केवल इसका लाभ उठाने के बजाय इसका उपयोग करें)।

लेकिन जिस ऑनलाइन जज में आप सॉफ्टवेयर डेवलप नहीं कर रहे हैं, आप एक ऐसा प्रोग्राम बना रहे हैं, जिसे करने में सक्षम होना चाहिए Microsoft सॉफ्टवेयर को 3 सेकंड में हासिल करने में 60 सेकंड लगते हैं !!!

तो, इस मामले में, सुनहरा नियम पसंद आता है (निश्चित रूप से यदि आप जावा का उपयोग करके और भी अधिक परेशानी में नहीं पड़ते हैं)

  • C ++ का उपयोग करें और समस्या को हल करने के लिए यह सब (और भारीपन / धीमापन) शक्ति का उपयोग करें
  • यदि आपको समय सीमित है, तो प्रिंटआउट और स्कैनफ के लिए डिब्बे और कौट्स को बदल दें (यदि आप क्लास स्ट्रिंग का उपयोग करके खराब हो जाते हैं, तो इस तरह प्रिंट करें: प्रिंटफ (% s, mystr.c_str ());
  • यदि आप अभी भी समय सीमित पाते हैं, तो कुछ स्पष्ट अनुकूलन करने की कोशिश करें (जैसे कि / जबकि / डॉवलेस या पुनरावर्ती कार्यों के लिए बहुत अधिक एम्बेडेड से बचना)। इसके अलावा संदर्भ वस्तुओं से गुजरना सुनिश्चित करें जो बहुत बड़ी हैं ...
  • यदि आपको अभी भी समय सीमित है, तो std :: vectors और c-arrays के लिए सेट बदलने का प्रयास करें।
  • यदि आपको अभी भी समय सीमित है, तो अगली समस्या पर जाएं ...

-2

अगर इससे भी scanfतेज होते cinतो भी कोई फर्क नहीं पड़ता। अधिकांश समय, आप हार्ड ड्राइव या कीबोर्ड से पढ़ रहे होंगे। अपने आवेदन में कच्चा डेटा प्राप्त करने से अधिक समय लगता है scanfऔर cinइसे संसाधित करने में अधिक समय लगता है।


पाइप के माध्यम से आईपीसी के बारे में क्या? क्या आपको लगता है कि वहाँ कोई ध्यान देने योग्य प्रदर्शन हो सकता है?
ड्रीमलैक्स

यहां तक ​​कि पाइप के माध्यम से आईपीसी के साथ, कर्नेल के अंदर और बाहर जाने में बहुत अधिक समय खर्च होता है, बस स्कैनफ / सिन के साथ पार्स करने से।
जे कॉनरोड

8
मैंने इस क्षेत्र में परीक्षण किया, और निश्चित रूप से कॉट एंड सिन के प्रदर्शन का प्रदर्शन किया। हालांकि उपयोगकर्ता इनपुट के लिए यह नगण्य है, यह निश्चित रूप से उन चीजों के लिए नहीं है जहां प्रदर्शन मायने रखता है। अन्य सी ++ फ्रेमवर्क मौजूद हैं जो हालांकि तेज हैं।
जोहान्स शाउब -

समस्या यह है कि hdd की तुलना iostream में धीमी है। हाँ, यह इतना ही चूसता है।
polkovnikov.ph
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.