पायथन से सी ++ में स्टडीन से बहुत धीमी गति से लाइनें क्यों पढ़ रही हैं?


1,267

मैं पायथन और सी ++ का उपयोग करके स्टडीन से स्ट्रिंग इनपुट की रीडिंग लाइनों की तुलना करना चाहता था और मेरे सी ++ कोड को बराबर पाइथन कोड की तुलना में धीमी गति के क्रम को चलाने के लिए चौंक गया था। चूंकि मेरा सी ++ जंगली है और मैं अभी तक एक विशेषज्ञ पायथनिस्ट नहीं हूं, कृपया मुझे बताएं कि क्या मैं कुछ गलत कर रहा हूं या अगर मैं कुछ गलत समझ रहा हूं।


(TLDR जवाब: बयान में शामिल हैं: cin.sync_with_stdio(false) या सिर्फ बजाय fgets का उपयोग

TLDR परिणाम:। मेरे सवाल का नीचे तक स्क्रॉल करते सभी तरह और टेबल को देखो।)


सी ++ कोड:

#include <iostream> 
#include <time.h> 

using namespace std; 

int main() { 
    string input_line; 
    long line_count = 0; 
    time_t start = time(NULL); 
    int sec; 
    int lps; 

    while (cin) { 
     getline(cin, input_line); 
     if (!cin.eof()) 
      line_count++; 
    }; 

    sec = (int) time(NULL) - start; 
    cerr << "Read " << line_count << " lines in " << sec << " seconds."; 
    if (sec > 0) { 
     lps = line_count/sec; 
     cerr << " LPS: " << lps << endl; 
    } else 
     cerr << endl; 
    return 0; 
} 

// Compiled with: 
// g++ -O3 -o readline_test_cpp foo.cpp 

अजगर समतुल्य:

#!/usr/bin/env python 
import time 
import sys 

count = 0 
start = time.time() 

for line in sys.stdin: 
    count += 1 

delta_sec = int(time.time() - start_time) 
if delta_sec >= 0: 
    lines_per_sec = int(round(count/delta_sec)) 
    print("Read {0} lines in {1} seconds. LPS: {2}".format(count, delta_sec, 
     lines_per_sec)) 

यहाँ मेरी परिणाम हैं:

$ cat test_lines | ./readline_test_cpp 
Read 5570000 lines in 9 seconds. LPS: 618889 

$cat test_lines | ./readline_test.py 
Read 5570000 lines in 1 seconds. LPS: 5570000 

संपादित करें:मैं नोट करना चाहिए कि मैं इस दोनों के तहत मैक   ओएस   एक्स   v10 की कोशिश की। 6.8 (हिम   तेंदुए) और लिनक्स 2.6.32 (रेड हैट लिनक्स 6.2)। पूर्व मैकबुक प्रो है, और बाद वाला एक बहुत ही मधुर सर्वर है, यह नहीं कि यह बहुत प्रासंगिक है।

संपादित करें 2:(यदि संपादन निकाला गया, अब भी लागू हो)

$ for i in {1..5}; do echo "Test run $i at `date`"; echo -n "CPP:"; cat test_lines | ./readline_test_cpp ; echo -n "Python:"; cat test_lines | ./readline_test.py ; done 
Test run 1 at Mon Feb 20 21:29:28 EST 2012 
CPP: Read 5570001 lines in 9 seconds. LPS: 618889 
Python:Read 5570000 lines in 1 seconds. LPS: 5570000 
Test run 2 at Mon Feb 20 21:29:39 EST 2012 
CPP: Read 5570001 lines in 9 seconds. LPS: 618889 
Python:Read 5570000 lines in 1 seconds. LPS: 5570000 
Test run 3 at Mon Feb 20 21:29:50 EST 2012 
CPP: Read 5570001 lines in 9 seconds. LPS: 618889 
Python:Read 5570000 lines in 1 seconds. LPS: 5570000 
Test run 4 at Mon Feb 20 21:30:01 EST 2012 
CPP: Read 5570001 lines in 9 seconds. LPS: 618889 
Python:Read 5570000 lines in 1 seconds. LPS: 5570000 
Test run 5 at Mon Feb 20 21:30:11 EST 2012 
CPP: Read 5570001 lines in 10 seconds. LPS: 557000 
Python:Read 5570000 lines in 1 seconds. LPS: 5570000 

संपादित करें 3:

ठीक है, मैं होने अजगर की कोशिश कर के जेएन के सुझाव की कोशिश की रेखा को पढ़ने के लिए स्टोर करें: लेकिन इससे पाइथन की गति में कोई फर्क नहीं पड़ता।

मैं भी बजाय एक char सरणी getline एक std::string में में scanf का उपयोग करने का जे.एन. के सुझाव की कोशिश की। बिंगो! इसके परिणामस्वरूप पायथन और सी ++ दोनों के बराबर प्रदर्शन हुआ। (3,333,333 एलपीएस मेरे इनपुट डेटा के साथ, जिस तरह से प्रत्येक तीन फ़ील्ड की छोटी लाइनें होती हैं, आमतौर पर लगभग 20 वर्ण चौड़ी होती हैं, हालांकि कभी-कभी अधिक)।

कोड:

char input_a[512]; 
char input_b[32]; 
char input_c[512]; 
while(scanf("%s %s %s\n", input_a, input_b, input_c) != EOF) { 
    line_count++; 
}; 

गति:

$ cat test_lines | ./readline_test_cpp2 
Read 10000000 lines in 3 seconds. LPS: 3333333 
$ cat test_lines | ./readline_test2.py 
Read 10000000 lines in 3 seconds. LPS: 3333333 

(हाँ, मैं इसे कई बार भाग गया।) तो, मुझे लगता है मैं अब scanf बजाय getline का प्रयोग करेंगे। लेकिन, मैं अभी भी उत्सुक हूं अगर लोग सोचते हैं कि यह प्रदर्शन std::string/getline से सामान्य और उचित है।

संपादित 4 (था: फाइनल संपादित करें/समाधान):

जोड़ना:

cin.sync_with_stdio(false); 
तुरंत अपने मूल से ऊपर

जबकि कोड है कि तेजी से अजगर से चलाता में परिणामों के ऊपर पाश।

नई प्रदर्शन तुलना (यह मेरे 2011 मैकबुक प्रो पर है) मूल कोड का उपयोग करके, सिंक अक्षम के साथ मूल, और मूल पायथन कोड क्रमशः 20 एम लाइनों वाली फ़ाइल पर फ़ाइल पर। हां, मैंने डिस्क कैशिंग confound को खत्म करने के लिए कई बार भाग लिया।

$ /usr/bin/time cat test_lines_double | ./readline_test_cpp 
     33.30 real   0.04 user   0.74 sys 
Read 20000001 lines in 33 seconds. LPS: 606060 
$ /usr/bin/time cat test_lines_double | ./readline_test_cpp1b 
     3.79 real   0.01 user   0.50 sys 
Read 20000000 lines in 4 seconds. LPS: 5000000 
$ /usr/bin/time cat test_lines_double | ./readline_test.py 
     6.88 real   0.01 user   0.38 sys 
Read 20000000 lines in 6 seconds. LPS: 3333333 

उनके जवाब के लिए @ वॉन कैटो के लिए धन्यवाद! कोई भी विस्तार करने वाले लोग या अच्छे संदर्भ दे सकते हैं, इस बात को इंगित कर सकते हैं कि यह सिंक्रनाइज़ेशन क्यों होता है, इसका क्या अर्थ है, जब यह उपयोगी होता है, और अक्षम होने के ठीक होने पर पोस्टरिटी द्वारा इसकी सराहना की जाएगी। :-)

संपादित 5/बेहतर समाधान:

Gandalf नीचे ग्रे ने सुझाव दिया है, gets भी तेजी से scanf या अनसिंक्रनाइज़्ड cin दृष्टिकोण से है। मैंने यह भी सीखा कि scanf और gets दोनों यूएनएसएएफई हैं और बफर ओवरफ्लो की संभावना के कारण उपयोग नहीं किया जाना चाहिए। इसलिए, मैंने fgets का उपयोग करके इस पुनरावृत्ति को लिखा, सुरक्षित विकल्प प्राप्त होता है। यहाँ मेरे साथी noobs के लिए उचित पंक्तियां हैं:

char input_line[MAX_LINE]; 
char *result; 

//<snip> 

while((result = fgets(input_line, MAX_LINE, stdin)) != NULL) 
    line_count++; 
if (ferror(stdin)) 
    perror("Error reading stdin."); 

अब, यहाँ एक और भी बड़ा फ़ाइल का उपयोग कर परिणाम (100M लाइनों; ~ 3.4   जीबी) कर रहे हैं बहुत तेजी से डिस्क के साथ एक तेजी से सर्वर पर, अजगर कोड की तुलना , unsynchronised cin, और fgets दृष्टिकोण, साथ ही साथ wc उपयोगिता की तुलना में। [scanf संस्करण विभाजन गलती है और मैं इसे समस्या निवारण की तरह महसूस नहीं करते।]:

$ /usr/bin/time cat temp_big_file | readline_test.py 
0.03user 2.04system 0:28.06elapsed 7%CPU (0avgtext+0avgdata 2464maxresident)k 
0inputs+0outputs (0major+182minor)pagefaults 0swaps 
Read 100000000 lines in 28 seconds. LPS: 3571428 

$ /usr/bin/time cat temp_big_file | readline_test_unsync_cin 
0.03user 1.64system 0:08.10elapsed 20%CPU (0avgtext+0avgdata 2464maxresident)k 
0inputs+0outputs (0major+182minor)pagefaults 0swaps 
Read 100000000 lines in 8 seconds. LPS: 12500000 

$ /usr/bin/time cat temp_big_file | readline_test_fgets 
0.00user 0.93system 0:07.01elapsed 13%CPU (0avgtext+0avgdata 2448maxresident)k 
0inputs+0outputs (0major+181minor)pagefaults 0swaps 
Read 100000000 lines in 7 seconds. LPS: 14285714 

$ /usr/bin/time cat temp_big_file | wc -l 
0.01user 1.34system 0:01.83elapsed 74%CPU (0avgtext+0avgdata 2464maxresident)k 
0inputs+0outputs (0major+182minor)pagefaults 0swaps 
100000000 


Recap (lines per second): 
python:   3,571,428 
cin (no sync): 12,500,000 
fgets:   14,285,714 
wc:   54,644,808 

आप देख सकते हैं, fgets बेहतर है, लेकिन अभी भी बहुत दूर WC प्रदर्शन से; मुझे पूरा यकीन है कि यह इस तथ्य के कारण है कि डब्ल्यूसी प्रत्येक चरित्र की किसी भी स्मृति प्रतिलिपि के बिना जांच करता है। मुझे संदेह है कि, इस बिंदु पर, कोड के अन्य हिस्सों में बाधा बन जाएगी, इसलिए मुझे नहीं लगता कि उस स्तर को अनुकूलित करना भी सार्थक होगा, भले ही संभव हो (क्योंकि, आखिर में, मुझे वास्तव में पढ़ने वाली रेखाओं को स्टोर करने की आवश्यकता है याद में)।

यह भी ध्यान रखें स्ट्रिंग के लिए एक char * बफर और fgets बनाम unsynchronised cin उपयोग करने के साथ एक छोटी सी दुविधा यह है कि कि बाद, किसी भी लम्बाई की तर्ज पढ़ सकते हैं पूर्व कुछ निश्चित संख्या के लिए इनपुट सीमित आवश्यकता है। व्यावहारिक रूप से, यह शायद अधिकांश लाइन-आधारित इनपुट फ़ाइलों को पढ़ने के लिए एक गैर-मुद्दा है, क्योंकि बफर को बहुत बड़े मान पर सेट किया जा सकता है जो मान्य इनपुट से अधिक नहीं होगा।

यह शैक्षिक रहा है। आपकी टिप्पणियों और सुझावों के लिए सभी को धन्यवाद।

संपादित 6:

नीचे टिप्पणी में J.F. सेबेस्टियन ने सुझाव दिया है, जीएनयू WC उपयोगिता के भीतर सादा सी read() (का उपयोग करता है सुरक्षित पढ़ें।सी रैपर) एक समय में भाग (16k बाइट्स) पढ़ने और नई लाइनों की गिनती करने के लिए। यहाँ एक अजगर बराबर जेएफ के कोड पर (सिर्फ प्रासंगिक स्निपेट कि अजगर for पाश की जगह दिखा आधारित है:

BUFFER_SIZE = 16384 
count = sum(chunk.count('\n') for chunk in iter(partial(sys.stdin.read, BUFFER_SIZE), '')) 

इस संस्करण के प्रदर्शन को काफी तेज है (हालांकि अभी भी एक सा कच्चे सी WC उपयोगिता की तुलना में धीमी , पाठ्यक्रम) का:

$ /usr/bin/time cat temp_big_file | readline_test3.py 
0.01user 1.16system 0:04.74elapsed 24%CPU (0avgtext+0avgdata 2448maxresident)k 
0inputs+0outputs (0major+181minor)pagefaults 0swaps 
Read 100000000 lines in 4.7275 seconds. LPS: 21152829 

फिर, यह थोड़ा मूर्खतापूर्ण है मुझे सी ++ fgets/cin और wc -l को एक हाथ पर पहले अजगर कोड और दूसरी ओर यह पिछले अजगर का टुकड़ा, की तुलना करने के लिए के रूप में बाद के दो वास्तव में पढ़ने की लाइनों को संग्रहीत न करें, लेकिन केवल न्यूलाइन की गणना करें। फिर भी, यह पूर्णांक है सभी विभिन्न कार्यान्वयन का पता लगाने और प्रदर्शन के प्रभाव के बारे में सोचने के लिए आराम कर रहे हैं। एक बार फिर धन्यवाद!

संपादित करें 7: टिनी बेंचमार्क परिशिष्ट और संक्षिप्त

पूर्णता के लिए, मैंने सोचा कि मैं मूल (सिंक किया गया) सी ++ कोड के साथ एक ही बॉक्स पर एक ही फाइल के लिए पढ़ने की गति को अद्यतन चाहते हैं। फिर, यह एक तेज डिस्क पर 100 एम लाइन फ़ाइल के लिए है। यहाँ पूरा तालिका अब है:

Implementation  Lines per second 
python (default)   3,571,428 
cin (default/naive)   819,672 
cin (no sync)    12,500,000 
fgets      14,285,714 
wc (not fair comparison) 54,644,808 
+7

क्या आपने कई बार अपने परीक्षण चलाए? शायद एक डिस्क कैश मुद्दा है। 21 feb. 122012-02-21 02:20:14

  0

@VaughnCato हाँ, और दो अलग-अलग मशीनों पर भी। 21 feb. 122012-02-21 02:22:39

  0

अपनी टेस्ट फ़ाइल को दूसरी, अलग फ़ाइल में कॉपी करने का प्रयास करें, ताकि उन्हें अलग से कैश किया जा सके। 21 feb. 122012-02-21 02:33:07

+5

@ जेजेसी: मुझे दो संभावनाएं दिखाई देती हैं (मान लीजिए कि आपने डेविड द्वारा सुझाए गए कैशिंग समस्या को हटा दिया है): 1) '<iostream> 'प्रदर्शन बेकार है। पहली बार ऐसा नहीं होता है। 2) पायथन पर्याप्त चालाक है कि डेटा को लूप में कॉपी न करें क्योंकि आप इसका उपयोग नहीं करते हैं। आप 'स्कैनफ़' और' char [] 'का उपयोग करने का प्रयास कर सकते हैं। वैकल्पिक रूप से आप लूप को फिर से लिखने का प्रयास कर सकते हैं ताकि स्ट्रिंग के साथ कुछ किया जा सके (उदाहरण के लिए 5 वां अक्षर रखें और परिणामस्वरूप इसे संयोजित करें)। 21 feb. 122012-02-21 02:35:47

+2

एक और बात यह है कि यह एक साधारण परीक्षण है जो वास्तव में भाषा एन बनाम भाषा एम के प्रदर्शन को प्रतिबिंबित नहीं करता है। पाइथन के पास उस सटीक मामले के लिए एक बहुत ही स्मार्ट अनुकूलन हो सकता है जो आपको पूर्ण विशेषीकृत एप्लिकेशन चलाते समय नहीं मिलेगा। 21 feb. 122012-02-21 02:39:59

+1

@JJC, आपको शायद 'datetime.datetime.now() के बजाय' time.time() 'का उपयोग करना चाहिए। सेकंड'; आपको फ्लोटिंग पॉइंट परिणाम मिलते हैं और एलपीएस गणना में विभाजित-शून्य-शून्य की संभावना नहीं होती है। मुझे अपनी मशीन पर समान परिणाम (पायथन लगभग 10x तेज) परीक्षण मिलता है। 21 feb. 122012-02-21 02:43:58

  0

@ जेएन। यदि मैं प्रत्येक पंक्ति से एक चरित्र एकत्र करता हूं तो पाइथन संस्करण अभी भी तेज़ है। 21 feb. 122012-02-21 02:48:52

+1

@ जेएन। पाइथन निश्चित रूप से डेटा कॉपी करने से बचने के लिए पर्याप्त स्मार्ट नहीं है। फ़ाइल के अलावा यह देखने के लिए पढ़ने की जरूरत है कि न्यूलाइन 21 feb. 122012-02-21 03:04:03

  0

कहां बड़ी हैं? जब तक लाइनें बहुत लंबी न हों, मुझे संदेह होगा कि यह एक कैशिंग मुद्दा हो सकता है। यानी कैश को 21 feb. 122012-02-21 03:06:32

  0

@gnibbler के बीच साफ़/फेंक दिया नहीं जाएगा: दो प्रतियां हैं और आप एक 21 feb. 122012-02-21 03:07:00

  0

बचा सकते हैं मुझे fscanf का उपयोग करके 3 गुना अंतर मिलता है। यह अजीब बात है क्योंकि किसी बिंदु पर पायथन को अंतर्निहित सी एपीआई का उपयोग करना चाहिए। 21 feb. 122012-02-21 03:08:21

  0

वास्तव में, एक बड़ी फ़ाइल का उपयोग करते समय 2 गुना (सटीक 1 सेकंड के साथ बहुत कम था)। 21 feb. 122012-02-21 03:14:10

  0

क्या यह संभव है कि पाइथन वीएम एक फ़ाइल को पाइप करते समय stdin के कुछ चालाक buffered पढ़ने करता है, तो इसे एक लाइन के प्रत्येक पढ़ने के लिए ड्राइव कैश में बाहर जाना नहीं है? 21 feb. 122012-02-21 03:14:20

+7

समस्या stdio के साथ सिंक्रनाइज़ेशन है - मेरा उत्तर देखें। 21 feb. 122012-02-21 03:30:51

  0

@brendanw, हाँ, लेकिन सी और सी ++ करते हैं। सी पायथन कार्यान्वयन लगभग निश्चित रूप से इसके लिए stdio पर निर्भर है। आधुनिक प्रणाली AFAIK में शामिल कैशिंग के कई स्तर हैं। 21 feb. 122012-02-21 03:39:29

+9

चूंकि किसी ने उल्लेख नहीं किया है कि आपको सी ++ के साथ अतिरिक्त लाइन क्यों मिलती है: ** 'cin.eof() 'के खिलाफ परीक्षण न करें !! **' ifline 'कॉल को' if' कथन में रखें। 21 feb. 122012-02-21 18:29:28

+14

'wc -l' तेज़ है क्योंकि यह एक समय में एक से अधिक पंक्ति को स्ट्रीम करता है (यह' फ्रेड (stdin)/memchr ('\ n') 'संयोजन हो सकता है)। पायथन परिणाम परिमाण के समान क्रम में हैं, ['wc-l.py'] (http://ideone.com/Ri0ia) 27 feb. 122012-02-27 00:21:23

  0

@ जेएफ। सेबेस्टियन उस पायथन कोड स्निपेट के लिए धन्यवाद! ऐसा लगता है कि डब्ल्यूसी सुरक्षित_read का उपयोग करता है, जो सादे पढ़ने के आसपास सिर्फ एक रैपर है, और एक समय में 16k पढ़ता है। 32k की बजाय 16k बफर का उपयोग करने के लिए अपने पाइथन कोड को संशोधित करना और उसी मशीन और परीक्षण फ़ाइल पर चलाना, क्रंच में 4 सेकंड (यानी 25,000,000 एलपीएस) धन्यवाद! 28 feb. 122012-02-28 00:26:03

  0

संबंधित प्रश्न: http: // stackoverflow।कॉम/प्रश्न/8310039/क्यों-डू-स्टडस्ट्रिंग-ऑपरेशंस-प्रदर्शन-खराब 11 mar. 122012-03-11 10:18:18

+1

"मेरा आई/ओ धीमा क्यों है?" का उत्तर लगभग हमेशा "बफरिंग" होता है। 12 mar. 122012-03-12 14:46:09

+2

वी, प्रसिद्ध सवाल! यदि आप डब्ल्यूसी की गति पर प्रदर्शन प्राप्त करना चाहते हैं, तो आप यह कर सकते हैं: लाइन-दर-लाइन फ़ंक्शंस को कॉल न करें, लेकिन बाइनरी ब्लॉक तैयार करें और उन्हें एक समय में एक int की जांच करें, जो कि एक्सओआर बिटमास्क का उपयोग करके उन्हें मास्क कर रहे हैं एक न्यूलाइन चरित्र। (यह आम तौर पर कम एकल बाइट fetches की ओर जाता है)। इसके अलावा, आपके द्वारा आवंटित किए गए बफर को इंगित करने के लिए अंतर्निहित फ़ंक्शंस का उपयोग करें। फिर आप इसे सीधे जांच सकते हैं। यदि आप वास्तव में stdio का दुरुपयोग करना चाहते हैं तो अधिक वूडू है, इसलिए आप सीमा को मारने के करीब भी नहीं आये हैं, लेकिन शायद आप डिस्क सीमा पर हैं इसलिए 26 apr. 122012-04-26 04:24:45

  0

@ std''rrgnlDave धन्यवाद, इन युक्तियों की आवाज़ होनहार! यदि आपको इनमें से कुछ को कार्यान्वित करने के लिए कोई आसान उदाहरण कोड लिखना/लिखना/ढूंढना है और इसे एक उत्तर (या कम से कम लिंक) के रूप में पोस्ट करना है, तो मैं और इस प्रश्न के भविष्य के पाठक आपके शिक्षण के लिए बहुत आभारी होंगे। चीयर्स! 26 apr. 122012-04-26 09:00:42

  0

पूर्णता के लिए, आप चार्ट में त्वरित पायथन संस्करण और समान सी ++ कोड क्यों नहीं जोड़ते हैं? आप चार्ट को शीर्ष पर ले जाने पर भी विचार कर सकते हैं, क्योंकि लोगों को इसे लंबे समय तक नहीं मिल सकता है। वास्तव में एक दिलचस्प पढ़ा! 14 jan. 142014-01-14 08:46:52

  0

http://stackoverflow.com/questions/21107131/why-mesh-python-code-slower-than-decomposed- के साथ आप किसी भी फ़ंक्शन में इसे निकालने के लिए पाइथन कोड को दो बार बढ़ा सकते हैं। 14 jan. 142014-01-14 18:23:01

  0

@ थॉमसएहले जो आप "त्वरित पायथन संस्करण" का जिक्र कर रहे हैं? सुझावों के लिए धन्यवाद, मैं चार्ट को शीर्ष पर कॉपी करूंगा। 15 jan. 142014-01-15 16:38:27

  0

@JCC I का अर्थ संपादित करना 6 16 jan. 142014-01-16 08:41:53

  0

से भी है, इसके अलावा, सी ++ बनाम पायथन में विभाजित लाइनों के बारे में मेरा अनुवर्ती प्रश्न देखें ... एक समान गति कहानी, जहां निष्क्रिय दृष्टिकोण सी ++ में धीमा है! यहां: http://stackoverflow.com/q/9378500/379037 27 jan. 152015-01-27 17:53:00

+1

यह वास्तव में बहुत ही शैक्षणिक है। और यह भी एक बार फिर इस तथ्य को रेखांकित करता है कि सी ++ शक्तिशाली है, लेकिन केवल तभी जब इसकी देखभाल में बहुत अच्छी देखभाल की जाती है। 05 aug. 152015-08-05 03:36:33

  0

यदि मैं आप थे, तो मैं mmap और memchr फ़ंक्शन को देखता हूं। चूंकि स्मृति कोई समस्या नहीं है, इसलिए एमएमएपी के साथ अपने प्रोग्राम में पूरी फ़ाइल को मैप करें, और फिर "रेखा सीमा" को समझने के लिए memchr का उपयोग करके प्रक्रिया करें। और यह भी कर्नेल को बताने के लिए तैयार है कि आप अनुक्रमिक रूप से 14 sep. 152015-09-14 15:33:29

  0

अच्छी पोस्ट पढ़ रहे हैं। लेकिन मैं बस यह उल्लेख करना चाहूंगा कि स्कैनफ के साथ बफर ओवरफ्लो समस्या को पढ़ने के लिए वर्णों की संख्या निर्दिष्ट करके (किसी भी डेटाटाइप के लिए) निर्दिष्ट किया जा सकता है। [Link] (http://www.cplusplus.com/reference/clibrary/cstdio/scanf/) में उल्लिखित चौड़ाई पैरामीटर देखें। एक उदाहरण के रूप में: चार एस [10]; scanf ("% 9 नंबर के पत्तों", रों); // यह इनपुट से 9 वर्णों पर पढ़ा जाएगा। int एक्स; scanf ("% 2d", &x); // यह इनपुट से 2 अंकों का नंबर पढ़ेगा। (बस उल्लेख कर रहा है) यह बफर ओवरफ़्लो का ख्याल रख सकता है। गतिशील चौड़ाई निर्दिष्ट नहीं की जा सकती है, लेकिन उस पर काबू पाने के लिए बस उत्पन्न हो सकता है 11 mar. 122012-03-11 18:05:28

1,134

डिफ़ॉल्ट रूप से, cin stdio है, जो इसे किसी भी इनपुट बफरिंग से बचने के लिए कारण बनता है से समन्वयित है। आप अपने मुख्य के शीर्ष करने के लिए इस जोड़ते हैं, तो कहीं बेहतर प्रदर्शन देखना चाहिए:

std::ios_base::sync_with_stdio(false); 

आम तौर पर, जब एक इनपुट स्ट्रीम बफ़र है, बजाय एक समय में एक चरित्र को पढ़ने में, धारा बड़ा पढ़ी जाएंगी मात्रा। इससे सिस्टम कॉल की संख्या कम हो जाती है, जो आमतौर पर अपेक्षाकृत महंगी होती है। हालांकि, FILE* आधारित stdio और iostreams के बाद अलग-अलग कार्यान्वयन होते हैं और इसलिए अलग-अलग बफर होते हैं, इससे दोनों एक साथ उपयोग किए जाने पर समस्या हो सकती है। उदाहरण के लिए:

int myvalue1; 
cin >> myvalue1; 
int myvalue2; 
scanf("%d",&myvalue2); 

तो अधिक इनपुट cin की तुलना में यह वास्तव में जरूरत द्वारा पढ़ा गया था, तो दूसरा पूर्णांक मान नहीं scanf समारोह है, जो अपनी स्वतंत्र बफर है के लिए उपलब्ध होगा। यह अप्रत्याशित परिणाम का कारण बन जाएगा।

इससे बचने के लिए, डिफ़ॉल्ट रूप से, धाराओं stdio के साथ सिंक्रनाइज़ कर रहे हैं। इसे प्राप्त करने का एक आम तरीका cinstdio फ़ंक्शंस का उपयोग करके आवश्यकतानुसार प्रत्येक वर्ण को पढ़ना है। दुर्भाग्य से, यह बहुत अधिक ओवरहेड पेश करता है। इनपुट की छोटी मात्रा के लिए, यह एक बड़ी समस्या नहीं है, लेकिन जब आप लाइनों के लाखों लोगों पढ़ रहे हैं, प्रदर्शन दंड महत्वपूर्ण है।

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

+90

यह शीर्ष पर होना चाहिए। यह लगभग निश्चित रूप से सही है। उत्तर 'fscanf' कॉल के साथ पढ़ने को बदलने में झूठ नहीं बोल सकता है, beca पाइथन के रूप में उतना ही काम नहीं करता है जितना कि काम करता है। पायथन को स्ट्रिंग के लिए मेमोरी आवंटित करनी चाहिए, संभवतः कई बार मौजूदा आवंटन अपर्याप्त समझा जाता है - बिल्कुल 'std :: string' के साथ C++ दृष्टिकोण की तरह। यह कार्य लगभग निश्चित रूप से I/O बाध्य है और सी ++ में 'std :: string' ऑब्जेक्ट्स बनाने या '<iostream>' का उपयोग करके लागत के बारे में बहुत अधिक FUD चल रहा है। 21 feb. 122012-02-21 03:34:32

+32

हां, इस लाइन को तुरंत मेरे मूल से ऊपर जोड़ते हुए, लूप ने कोड को भी पाइथन को पार करने के लिए बढ़ाया। मैं परिणाम को अंतिम संपादन के रूप में पोस्ट करने जा रहा हूं। एक बार फिर धन्यवाद! 21 feb. 122012-02-21 03:45:25

+5

मुझे एक अच्छा संदर्भ नहीं मिला, लेकिन मैंने अपनी समझ के आधार पर कुछ स्पष्टीकरण जोड़ा। 21 feb. 122012-02-21 04:34:19

  0

@VaughnCato यह पता चला है कि fgets भी तेज है, कृपया मेरा संपादन 5 देखें। फिर भी, आपका समाधान बहुत उपयोगी है, esp। जब किसी को सिन का उपयोग करने और स्ट्रिंग ऑब्जेक्ट को लिखने की आवश्यकता होती है, उदा। संदर्भों में जहां एक एकल रेखा अनुमानित रूप से अनुमानित रूप से अधिक लंबी हो सकती है और जहां fgets -> char buffer [MAXLINE] मार्ग का परिणाम छंटनी होगा। धन्यवाद। 22 feb. 122012-02-22 11:47:50

+1

100 वें अपवोट और आपके लिए एक अच्छा बैज अच्छा सर। 11 mar. 122012-03-11 07:38:51

  0

आउटपुट/प्रिंटिंग के बारे में क्या? क्योंकि मुझे लगता है कि गिनती भी धीमी है, क्या यह वही है? 11 mar. 122012-03-11 12:31:20

+4

हां, यह वास्तव में कोउट, सीर, और क्लोग पर भी लागू होता है। 11 mar. 122012-03-11 13:56:11

+2

कोउट, सीन, सीर और क्लोग तेज़ी से बनाने के लिए, इसे इस तरह से करें std :: ios_base :: sync_with_stdio (false); 11 mar. 122012-03-11 14:17:35

  0

खुशी है कि मैं इस क्यू एंड ए में भाग गया। बस याद रखें कि यदि आप cin.sync_with_stdio (false) समाधान का उपयोग करते हैं तो आपके प्रोग्राम का कोई अन्य हिस्सा stdin से पढ़ना चाहिए! स्ट्रीम सिंक पर एक उत्कृष्ट लेख http://drdobbs.com/184401305 13 mar. 122012-03-13 17:09:56

  0

पर पाया जा सकता है, मैं इसके लिए अपने दैनिक वोटों में से एक को जलाऊंगा, और मैं यहां तक ​​कि खोज पर भी नहीं पहुंचा, बस इसे संभवतः देखा एक पूरी तरह से मनमाना सवाल से संबंधित सूची। यह * अविश्वसनीय रूप से * लोगों के लिए गति-संवेदनशील 'सिने' इनपुट करने में मददगार है और बफरिंग के लाभ चाहते हैं। बहुत बहुत धन्यवाद, वॉन। भयानक जवाब। 24 jun. 132013-06-24 20:06:48

+25

ध्यान दें कि 'sync_with_stdio()' एक स्थिर सदस्य फ़ंक्शन है, और किसी भी स्ट्रीम ऑब्जेक्ट (उदा। 'Cin') पर इस फ़ंक्शन पर कॉल * सभी * मानक iostream ऑब्जेक्ट्स के लिए सिंक्रनाइज़ेशन को चालू या बंद करता है। 21 jan. 152015-01-21 01:16:26

  0

@gjpc गलत; अगर सिंक्रनाइज़ेशन की मेरी समझ सही है, तो आप तब भी ऐसा करने के लिए स्वतंत्र हैं जब तक कि यह 'std :: cin.rdbuf()' पर निर्भर करता है। आप सिर्फ cstdio के 'stdin' का उपयोग नहीं कर सकते हैं। 08 apr. 172017-04-08 15:34:15

  0

(_ps.s._ न ही 'std :: wcin'।) 08 apr. 172017-04-08 15:44:31


4

एक जवाब का एक पहला तत्व: <iostream> धीमी है। धीमा मुझे नीचे दिए गए scanf के साथ एक बड़ा प्रदर्शन बढ़ावा मिलता है, लेकिन यह अभी भी पाइथन से दो गुना धीमा है।

#include <iostream> 
#include <time.h> 
#include <cstdio> 

using namespace std; 

int main() { 
    char buffer[10000]; 
    long line_count = 0; 
    time_t start = time(NULL); 
    int sec; 
    int lps; 

    int read = 1; 
    while(read > 0) { 
     read = scanf("%s", buffer); 
     line_count++; 
    }; 
    sec = (int) time(NULL) - start; 
    line_count--; 
    cerr << "Saw " << line_count << " lines in " << sec << " seconds." ; 
    if (sec > 0) { 
     lps = line_count/sec; 
     cerr << " Crunch speed: " << lps << endl; 
    } 
    else 
     cerr << endl; 
    return 0; 
} 
  0

जब तक मैंने अपना तीसरा संपादन नहीं किया, तब तक यह पोस्ट नहीं देखा, लेकिन आपके सुझाव के लिए फिर से धन्यवाद। आश्चर्यजनक रूप से, मेरे ऊपर बनाम पायथन के लिए 2x हिट नहीं है, अब ऊपर संपादित 3 में स्कैनफ लाइन के साथ। मैं 2.7 का उपयोग कर रहा हूं रास्ता। 21 feb. 122012-02-21 03:32:48

+7

सी ++ संस्करण को ठीक करने के बाद, यह stdio संस्करण मेरे कंप्यूटर पर C++ iostreams संस्करण से काफी धीमा है। (3 सेकंड बनाम 1 सेकंड) 21 feb. 122012-02-21 03:39:13

+3

वही है। stdio को सिंक चाल थी। 21 feb. 122012-02-21 04:08:57

  0

fgets भी तेज़ है; कृपया उपरोक्त संपादन 5 देखें। धन्यवाद। 22 feb. 122012-02-22 11:49:20


5

आपके दूसरे उदाहरण (स्कैनफ़() के साथ) कारण यह अभी भी धीमा हो सकता है क्योंकि स्कैनफ़ ("% s") स्ट्रिंग पार्स करता है और किसी भी स्पेस चार (स्पेस, टैब, न्यूलाइन) की तलाश करता है।

इसके अलावा, हाँ, सीपीथॉन हार्डडिस्क पढ़ने से बचने के लिए कुछ कैशिंग करता है।


64

मै मैक पर g ++ का उपयोग करके अपने कंप्यूटर पर मूल परिणाम दोहराया।

बस से पहले while पाश सी ++ संस्करण के लिए निम्नलिखित बयानों जोड़ने इनलाइन लाता Python संस्करण के साथ:

std::ios_base::sync_with_stdio(false); 
char buffer[1048576]; 
std::cin.rdbuf()->pubsetbuf(buffer, sizeof(buffer)); 

sync_with_stdio सुधार की गति 2 सेकंड, और एक बड़ा बफर की स्थापना 1 सेकंड के लिए इसे नीचे लाया ।

+3

आप अधिक उपयोगी जानकारी प्राप्त करने के लिए अलग-अलग बफर आकारों को आजमा सकते हैं। मुझे संदेह है कि आप तेजी से कम रिटर्न देखेंगे। 21 feb. 122012-02-21 03:37:59

+6

मैं अपने जवाब में बहुत जल्दबाजी में था; डिफॉल्ट के अलावा बफर आकार को किसी अन्य चीज़ पर सेट करने से सराहनीय अंतर नहीं हुआ। 21 feb. 122012-02-21 03:51:45

+80

मैं स्टैक पर 1 एमबी बफर स्थापित करने से भी बचूंगा। यह स्टैक ओवरफ्लो का कारण बन सकता है (हालांकि मुझे लगता है कि यह इसके बारे में बहस करने के लिए एक अच्छी जगह है!) 21 feb. 122012-02-21 07:30:30

+8

मैथ्यूयू, मैक डिफ़ॉल्ट रूप से 8 एमबी प्रोसेस स्टैक का उपयोग करता है। लिनक्स प्रति थ्रेड डिफ़ॉल्ट 4 एमबी का उपयोग करता है, आईआईआरसी। 1 एमबी उस प्रोग्राम के लिए बहुत अधिक मुद्दा नहीं है जो अपेक्षाकृत उथले ढेर गहराई के साथ इनपुट को बदलता है। सबसे महत्वपूर्ण बात यह है कि, यदि बफर गुंजाइश से बाहर हो जाता है तो std :: cin ढेर को मिटा देगा। 14 jan. 142014-01-14 09:28:54

+17

@SEK विंडोज डिफ़ॉल्ट स्टैक आकार 1 एमबी है। 15 mar. 142014-03-15 02:11:35

+1

यह ध्यान दिया जाना चाहिए कि सीन के बफर पर पबेटबफ के प्रभाव मानकीकृत नहीं हैं। कार्यान्वयन वास्तव में प्रदत्त बफर का उपयोग कर सकता है, इसे अनदेखा कर सकता है (जो std :: basic_streambuf से विरासत में डिफ़ॉल्ट कार्रवाई होगी), या संभवतः कुछ और भी कर सकता है। यह भी देखें http://stackoverflow.com/questions/12481463/stringstream-rdbuf-pubsetbuf-is-not-setting-the-buffer 09 jun. 152015-06-09 18:10:23

+1

@SEK की 'अधिक महत्वपूर्ण' को हाइलाइट करने के लिए: टिप्पणी: यदि बफर स्टैक पर है , आप फ़ंक्शन को बंद होने तक फ़ंक्शन को वापस करने की अनुमति नहीं दे सकते हैं, या बफर का उपयोग अन्यथा बंद कर दिया जाता है। 22 sep. 172017-09-22 22:10:38


2

ठीक है, मुझे लगता है कि आपके दूसरे समाधान में आपने cin से scanf पर स्विच किया था, जो पहला सुझाव था जिसे मैं आपको बनाने के लिए जा रहा था (cin sloooooooooooow) है। अब, यदि आप scanf से fgets पर स्विच करते हैं, तो आप प्रदर्शन में एक और बढ़ावा देखेंगे: fgets स्ट्रिंग इनपुट के लिए सबसे तेज़ C++ फ़ंक्शन है।

बीटीडब्ल्यू, उस सिंक चीज़ के बारे में नहीं पता था, अच्छा। लेकिन आपको अभी भी fgets आज़माएं।

+4

बढ़िया! यद्यपि() खराब हो जाता है (हम सभी को फ़ैक्स का उपयोग करना चाहिए, ताकि वेक्सर्स को विफल कर सकें), मैंने fgets का उपयोग करके कार्यान्वित किया और मुझे बेहतर प्रदर्शन दिखाई दे रहा है। कृपया मेरा नवीनतम संपादन (5) ऊपर देखें। इस पर ध्यान दिलाने के लिए धन्यवाद! 22 feb. 122012-02-22 11:22:36

+51

आपको *********** कभी भी *********** 'get' का उपयोग करना चाहिए। अप्रतिबंधित बफर इनपुट एक गंभीर समस्या है और 'हो जाता है' एक प्रमुख योगदानकर्ता है। 11 mar. 122012-03-11 07:44:46

+7

जब तक आप अपने प्रोग्राम में बफर ओवरफ्लो भेद्यता नहीं चाहते हैं तब तक कभी भी इसका उपयोग न करें। जीसीसी आपको संकलित समय पर प्राप्त होने के बारे में चेतावनी देता है भले ही आपके पास कोई चेतावनी झंडे स्थापित न हों। 11 mar. 122012-03-11 07:55:37

+1

आप लोग बिल्कुल सही हैं। मैंने सुझाव दिया कि यह एक आसान बेंचमार्किंग था, न कि उत्पादन कोड, लेकिन मेरा जवाब अनुभवहीन प्रोग्रामर को उत्पादन कोड में 'होट' का उपयोग करने का नेतृत्व कर सकता है। मैंने इसके बजाय सुरक्षित संस्करण ('fgets') का सुझाव देने के लिए इसे संपादित किया। आपका बहुत बहुत धन्यवाद!! 30 aug. 172017-08-30 00:17:39


7

वैसे, कारण सी ++ संस्करण के लिए लाइन गिनती पाइथन संस्करण के लिए गिनती से अधिक है क्योंकि ईओएफ ध्वज केवल ईओ से परे पढ़ने के लिए प्रयास किए जाने पर सेट हो जाता है। तो सही पाश होगा:

while (cin) { 
    getline(cin, input_line); 

    if (!cin.eof()) 
     line_count++; 
}; 
+45

वास्तव में सही पाश होगा: 'जबकि (getline (cin, input_line)) line_count ++;' 05 may. 122012-05-05 14:42:01


87

बस जिज्ञासा से बाहर मैं क्या हुड के नीचे होता है पर एक नज़र डाली है, और मैं प्रत्येक परीक्षा पर dtruss/strace का उपयोग किया है।

सी ++

./a.out < in 
Saw 6512403 lines in 8 seconds. Crunch speed: 814050 

syscalls sudo dtruss -c ./a.out < in

CALL          COUNT 
__mac_syscall         1 
<snip> 
open           6 
pread           8 
mprotect          17 
mmap           22 
stat64           30 
read_nocancel        25958 

अजगर

./a.py < in 
Read 6512402 lines in 1 seconds. LPS: 6512402 

syscalls sudo dtruss -c ./a.py < in

CALL          COUNT 
__mac_syscall         1 
<snip> 
open           5 
pread           8 
mprotect          17 
mmap           21 
stat64           29 

15

getline, स्ट्रीम ऑपरेटर, scanf, यदि आप फ़ाइल लोडिंग समय की परवाह नहीं करते हैं या यदि आप छोटी टेक्स्ट फ़ाइलों को लोड कर रहे हैं तो सुविधाजनक हो सकता है। लेकिन, यदि प्रदर्शन ऐसा कुछ है जिसके बारे में आप परवाह करते हैं, तो आपको वास्तव में पूरी फ़ाइल को स्मृति में बफर करना चाहिए (माना जाता है कि यह फिट होगा)।

यहाँ एक उदाहरण है:

//open file in binary mode 
std::fstream file(filename, std::ios::in|::std::ios::binary); 
if(!file) return NULL; 

//read the size... 
file.seekg(0, std::ios::end); 
size_t length = (size_t)file.tellg(); 
file.seekg(0, std::ios::beg); 

//read into memory buffer, then close it. 
char *filebuf = new char[length+1]; 
file.read(filebuf, length); 
filebuf[length] = '\0'; //make it null-terminated 
file.close(); 

यदि आप चाहते हैं, तो आपको स्ट्रीम कि बफर के आसपास इस तरह और अधिक सुविधाजनक उपयोग करने के लिए लपेट कर सकते हैं:

std::istrstream header(&buffer[0], length); 

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


4

निम्न कोड यहां दिए गए अन्य कोड की तुलना में मेरे लिए निम्न कोड तेज था: (दृश्य स्टूडियो 2013, 64-बिट, 500 एमबी फ़ाइल लाइन लंबाई के साथ समान रूप से [0, 1000) में)।

const int buffer_size = 500 * 1024; // Too large/small buffer is not good. 
std::vector<char> buffer(buffer_size); 
int size; 
while ((size = fread(buffer.data(), sizeof(char), buffer_size, stdin)) > 0) { 
    line_count += count_if(buffer.begin(), buffer.begin() + size, [](char ch) { return ch == '\n'; }); 
} 

यह एक कारक की तुलना में अधिक 2.


44

मैं कुछ साल यहां के पीछे कर रहा हूँ द्वारा अपने सभी अजगर प्रयास धड़कता है, लेकिन:

की में '4/5/6 संपादित करें'

    :

    $ /usr/bin/time cat big_file | program_to_benchmark 
    

    यह अलग अलग तरीकों की एक जोड़ी में गलत है: मूल पोस्ट है, तो आप उपयोग कर रहे हैं निर्माण

  1. आप वास्तव में 'बिल्ली' के निष्पादन का समय दे रहे हैं, न कि आपके बेंचमार्क। `उपयोगकर्ता 'और' sys 'CPU उपयोग' टाइम` द्वारा प्रदर्शित '` cat` के हैं, न कि आपके बेंचमार्क किए गए प्रोग्राम। इससे भी बदतर, 'असली' समय भी जरूरी नहीं है। आपके स्थानीय ओएस में 'बिल्ली' और पाइपलाइनों के कार्यान्वयन के आधार पर, यह संभव है कि 'बिल्ली' एक अंतिम विशाल बफर लिखता है और पाठक प्रक्रिया अपने काम को पूरा करने से बहुत पहले बाहर निकलता है।

  2. `बिल्ली` का उपयोग अनावश्यक है और वास्तव में प्रतिकूल है; आप चलती भागों को जोड़ रहे हैं। यदि आप पर्याप्त पुरानी प्रणाली पर थे (यानी एक सिंगल सीपीयू के साथ - - कंप्यूटर की कुछ पीढ़ियों में - I/O CPU से तेज़) - केवल तथ्य यह है कि 'बिल्ली' चल रहा था, परिणाम को काफी हद तक रंग सकता था। आप जो भी इनपुट और आउटपुट बफरिंग और अन्य प्रसंस्करण 'बिल्ली' कर सकते हैं के अधीन भी हैं। (यह संभव है कि आप पुरस्कार एक 'बिल्ली के अनुपयोगी प्रयोग करें' की कमाई कर ली है कि अगर मैं रैंडल श्वार्ट्ज थे: https://en.wikipedia.org/wiki/Cat_(Unix)#Useless_use_of_cat)

एक बेहतर निर्माण होगा:

$ /usr/bin/time program_to_benchmark < big_file 

इस बयान में यह खोल है जो big_file खोलता है, इसे आपके प्रोग्राम में पास कर रहा है (ठीक है, वास्तव में 'समय' जो तब आपके प्रोग्राम को उपप्रोसेसर के रूप में निष्पादित करता है) पहले से ही खुली फ़ाइल डिस्क्रिप्टर के रूप में। फ़ाइल पढ़ने का 100% सख्ती से उस कार्यक्रम की ज़िम्मेदारी है जिसे आप बेंचमार्क करने का प्रयास कर रहे हैं। यह आपको नकली जटिलताओं के बिना अपने प्रदर्शन का वास्तविक पढ़ने देता है।

मैं दो संभव है, लेकिन वास्तव में गलत, 'फिक्स' जो भी माना जा सकता है उल्लेख होगा (लेकिन मैं 'संख्या' उन्हें अलग तरह से के रूप में इन बातों को जो मूल पोस्ट में गलत थे नहीं हैं):

$ cat big_file | /usr/bin/time program_to_benchmark 

बी या पूरे पाइपलाइन समय से:

$ /usr/bin/time sh -c 'cat big_file | program_to_benchmark' 

इन # 2 के रूप में एक ही कारण के लिए गलत हैं: आप केवल अपने कार्यक्रम समय से इस 'ठीक' कर सकता है वे सेंट रहे हैं अनावश्यक रूप से 'बिल्ली' का उपयोग कर बीमार।मैं उन्हें कुछ कारणों का उल्लेख:

  • वे अधिक लोगों के लिए 'प्राकृतिक' जो पूरी तरह POSIX खोल

  • मामलों हो सकता है की मैं/हे पुनर्निर्देशन सुविधाओं के साथ सहज नहीं हैं, जहां `cat` आवश्यक है (उदाहरण: फ़ाइल को पढ़ने के लिए कुछ प्रकार के विशेषाधिकारों की आवश्यकता होती है, और आप प्रोग्राम को उस विशेषाधिकार को बेंचमार्क नहीं करना चाहते हैं: 'सुडो बिल्ली/देव/एसडीए |/usr/bin/time my_compression_test --no-output`)

  • इन कि कुछ झिझक के साथ आखिरी बात अभ्यास, आधुनिक मशीनों पर कहा, `पाइप लाइन में cat` कोई वास्तविक परिणाम

की शायद है लेकिन मैं कहता हूँ।

$ /usr/bin/time cat temp_big_file | wc -l 
0.01user 1.34system 0:01.83elapsed 74%CPU ... 

- - हम 'संपादन 5' में अंतिम परिणाम की जांच यदि यह है कि `cat` भस्म परीक्षण के दौरान सीपीयू के 74% का दावा है; और वास्तव में 1.34/1.83 लगभग 74% है। शायद की एक रन:

$ /usr/bin/time wc -l < temp_big_file 

ही शेष .49 सेकंड ले लिया होता! शायद नहीं: यहां 'बिल्ली' को पढ़ने() सिस्टम कॉल (या समतुल्य) के लिए भुगतान करना पड़ा जो फ़ाइल को 'डिस्क' (वास्तव में बफर कैश) से स्थानांतरित कर देता था, साथ ही साथ पाइप उन्हें 'wc` तक पहुंचाने के लिए लिखता था। सही परीक्षण को अभी भी उन पढ़ने() कॉल करना पड़ता था; केवल लिखने के लिए-पाइप और रीड-ऑफ-पाइप कॉल सहेजे गए होंगे, और उनको बहुत सस्ता होना चाहिए।

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

असल में मैंने लिनक्स 3.13 (उबंटू 14.04) सिस्टम पर 1.5 गीगाबाइट फ़ाइल कचरा के साथ कुछ त्वरित परीक्षण किए, इन परिणामों को प्राप्त करने (ये वास्तव में '3 का सबसे अच्छा परिणाम हैं; कैश को प्राथमिकता देने के बाद, निश्चित रूप से):

$ time wc -l < /tmp/junk 
real 0.280s user 0.156s sys 0.124s (total cpu 0.280s) 
$ time cat /tmp/junk | wc -l 
real 0.407s user 0.157s sys 0.618s (total cpu 0.775s) 
$ time sh -c 'cat /tmp/junk | wc -l' 
real 0.411s user 0.118s sys 0.660s (total cpu 0.778s) 

सूचना है कि दो पाइप लाइन परिणाम वास्तविक समय की तुलना में अधिक CPU समय (उपयोगकर्ता + sys ले लिया है करने के लिए) का दावा है। ऐसा इसलिए है क्योंकि मैं शैल (बैश) के अंतर्निर्मित 'समय' कमांड का उपयोग कर रहा हूं, जो पाइपलाइन के संज्ञेय है; और मैं एक मल्टी कोर मशीन जहां एक पाइप लाइन में अलग प्रक्रियाओं अलग कोर का उपयोग कर सकते है, तेजी से वास्तविक समय की तुलना में CPU समय जमा पर कर रहा हूँ। दिखा रहा है कि यह केवल समय ही पाइप लाइन तत्व अपने कमांड लाइन पर यह करने के लिए पारित किया जा सकता है -/usr/bin/बार मैं वास्तविक समय की तुलना में छोटे CPU समय को देखने का उपयोग करना। इसके अलावा, खोल का आउटपुट मिलीसेकंड देता है जबकि/usr/bin/time केवल एक सेकंड की हंडरथ देता है।

तो 'wc -l` के दक्षता स्तर पर,' बिल्ली 'एक बड़ा अंतर बनाता है: 40 9/283 = 1.453 या 45.3% अधिक वास्तविक समय, और 775/280 = 2.768, या एक विशाल 177% अधिक CPU उपयोग किया गया! मेरे यादृच्छिक पर-पर-समय-समय पर परीक्षण बॉक्स था।

मैं जोड़ने चाहिए परीक्षण के इन शैलियों के बीच कम से कम एक अन्य महत्वपूर्ण अंतर यह है कि, और मैं यह नहीं कह सकते कि क्या यह एक लाभ या गलती है; आप स्वयं इस निर्णय करना है:

जब आप चलाने के `बिल्ली big_file |/Usr/bin/समय my_program`, अपने कार्यक्रम एक पाइप से इनपुट प्राप्त कर रहा है, ठीक `cat` द्वारा भेजे गए गति से, और मात्रा में कोई` cat` द्वारा लिखित से भी बड़ा।

जब आप `/ usr/bin/time my_program < big_file` चलाते हैं, तो आपके प्रोग्राम को वास्तविक फ़ाइल में एक खुली फ़ाइल डिस्क्रिप्टर प्राप्त होती है। आपके कार्यक्रम - या कई मामलों में आई/ओ पुस्तकालयों में जिस भाषा में लिखा गया था - एक नियमित फ़ाइल का संदर्भ देने वाले फाइल डिस्क्रिप्टर के साथ प्रस्तुत किए जाने पर अलग-अलग कार्रवाइयां कर सकती हैं। यह स्पष्ट पढ़ने (2) सिस्टम कॉल का उपयोग करने के बजाय, इनपुट फ़ाइल को अपने पता स्थान में मैप करने के लिए mmap (2) का उपयोग कर सकता है। 'मतभेद' बाइनरी चलाने की छोटी लागत के मुकाबले इन मतभेदों के आपके बेंचमार्क परिणामों पर बहुत बड़ा प्रभाव हो सकता है।

बेशक यह एक दिलचस्प बेंचमार्क परिणाम है यदि एक ही कार्यक्रम दो मामलों के बीच काफी अलग प्रदर्शन करता है। यह दिखाता है कि, वास्तव में, कार्यक्रम या उसके आई/ओ पुस्तकालय कुछ दिलचस्प कर रहे हैं, जैसे mmap() का उपयोग करना। तो व्यवहार में दोनों तरीकों से बेंचमार्क चलाने के लिए अच्छा हो सकता है; शायद 'बिल्ली' के परिणाम को 'बिल्ली' चलाने की लागत को "क्षमा" करने के लिए कुछ छोटे कारकों के परिणामस्वरूप छूट।

+6

वाह, वह काफी अंतर्दृष्टिपूर्ण था! हालांकि मुझे पता चला है कि कार्यक्रमों के स्टडीन में इनपुट को खिलाने के लिए बिल्ली अनावश्यक है और <शेल रीडायरेक्ट को प्राथमिकता दी जाती है, मैं आम तौर पर डेटा के बाएं से दाएं प्रवाह के कारण बिल्ली पर फंस गया हूं कि पूर्व विधि दृष्टि से संरक्षित है जब मैं पाइपलाइनों के बारे में सोचता हूं। ऐसे मामलों में प्रदर्शन मतभेद मुझे नगण्य पाया गया है। लेकिन, मैं आपको शिक्षित करने की सराहना करता हूं, बेला। 09 may. 172017-05-09 01:16:09

+1

मैं व्यक्तिगत रूप से एक उपरोक्त से बच जाऊंगा, क्योंकि यह मूल प्रश्न को संबोधित नहीं करता है (ध्यान दें कि बिल्ली का उपयोग प्रतियोगी उदाहरणों में निरंतर है)। लेकिन, फिर, * निक्स के इन्स और बहिष्कारों के बारे में बौद्धिक चर्चा के लिए धन्यवाद। 09 may. 172017-05-09 01:18:24

+4

रीडायरेक्शन को प्रारंभिक चरण में शेल कमांड लाइन से बाहर निकाला जाता है, जो आपको इनमें से एक करने की अनुमति देता है, अगर यह बाएं से दाएं प्रवाह की अधिक आकर्षक उपस्थिति देता है: '$ <big_file time my_program' ' $ time <big_file my_program' यह किसी भी POSIX खोल में काम करना चाहिए (यानी \ 'csh \' नहीं और मुझे exotica \ \ rc \ 'की तरह निश्चित नहीं है:) 10 may. 172017-05-10 21:55:01

+3

फिर, शायद अनजान वृद्धिशील प्रदर्शन अंतर से अलग एक ही समय में चल रही \ 'बिल्ली \ 'बाइनरी के कारण, आप इनपुट फ़ाइल को mmap() करने में सक्षम होने के परीक्षण के तहत प्रोग्राम की संभावना छोड़ रहे हैं। इससे परिणामों में गहरा अंतर हो सकता है। यह सच है भले ही आपने खुद को बेंचमार्क लिखा है, विभिन्न भाषाओं में, केवल 'फ़ाइल से इनपुट लाइन' idiom का उपयोग करके। यह उनके विभिन्न I/O पुस्तकालयों के विस्तृत कार्यों पर निर्भर करता है। 10 may. 172017-05-10 22:01:02