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


20

मैंने पायथन की तरह की कार्यक्षमता की गति का परीक्षण करने के लिए निम्नलिखित स्क्रिप्ट लिखी है:

from sys import stdin, stdout
lines = list(stdin)
lines.sort()
stdout.writelines(lines)

मैंने इसके बाद sort10 मिलियन लाइनों वाली फाइल पर कोरुटिल्स कमांड की तुलना की :

$ time python sort.py <numbers.txt >s1.txt
real    0m16.707s
user    0m16.288s
sys     0m0.420s

$ time sort <numbers.txt >s2.txt 
real    0m45.141s
user    2m28.304s
sys     0m0.380s

अंतर्निहित कमांड में सभी चार सीपीयू (पायथन केवल एक का उपयोग किया गया) का उपयोग किया गया था, लेकिन इसे चलाने में लगभग 3 गुना समय लगा! क्या देता है?

मैं Ubuntu 12.04.5 (32-बिट), पायथन 2.7.3 और sort8.13 का उपयोग कर रहा हूं


@goldilocks हां यह है, उपयोगकर्ता बनाम वास्तविक समय को देखें।
अगस्तुर

हुह - तुम सही हो। जाहिरा तौर पर यह कोरुटिल्स 8.6 में समानांतर किया गया था।
गोल्डीलॉक्स

क्या आप --buffer-sizeयह निर्दिष्ट करने के लिए उपयोग कर सकते हैं कि sortसभी उपलब्ध भौतिक मेमोरी का उपयोग करें और देखें कि क्या मदद करता है?
इरूवर

@ 1_CR ने इसे 1 GB बफ़र के साथ आज़माया, समय में कोई महत्वपूर्ण परिवर्तन नहीं हुआ। यह केवल के बारे में .6 GB का उपयोग करता है, इसलिए बफर आकार को बढ़ाने से मदद नहीं मिलेगी।
२०:०२ पर अगस्त

जवाबों:


22

इज़्काता की टिप्पणी से उत्तर का पता चला: स्थानीय-विशिष्ट तुलना। sortआदेश एक बाइट क्रम तुलना करने के लिए स्थान के वातावरण ने संकेत दिया है, जबकि अजगर चूक उपयोग करता है। यूटीएफ -8 तार की तुलना बाइट तार की तुलना में कठिन है।

$ time (LC_ALL=C sort <numbers.txt >s2.txt)
real    0m5.485s
user    0m14.028s
sys     0m0.404s

उस के बारे में कैसा है।


और वे UTF-8 स्ट्रिंग्स के लिए तुलना कैसे करते हैं?
गाइल्स 'एसओ- बुराई को रोकना'

@Gilles locale.strxfrmसॉर्ट करने के लिए पायथन स्क्रिप्ट को संशोधित करते हुए , स्क्रिप्ट ने ~ 32 सेकंड का समय लिया, फिर भी तेजी से sortकम लेकिन बहुत कम।
अगुरार

3
पायथन 2.7.3 बाइट तुलना कर रहा है, लेकिन पायथन 3 यूनिकोड शब्द की तुलना कर रहा है। Python3.3 इस "परीक्षण" के लिए धीमी गति से Python2.7 से दोगुना है। यूनिकोड प्रतिनिधित्व में कच्चे बाइट्स को पैक करने का ओवरहेड पहले से ही महत्वपूर्ण पैकिंग वस्तुओं की तुलना में अधिक है जो पायथन 2.7.3 को करना है।
एन्थॉन

2
मुझे वही धीमे-धीमे साथ मिला cut, और दूसरों को भी। कई मशीनों पर अब मेरे पास export LC_ALL=Cहै .bashrc। लेकिन खबरदार: यह अनिवार्य रूप से टूट जाता है wc(को छोड़कर wc -l), बस एक उदाहरण का नाम देने के लिए। "बैड बाइट्स" को बिल्कुल भी नहीं गिना जाता ...
वाल्टर ट्रॉस

1
इस प्रदर्शन समस्या भी साथ होता है grep: यदि आप एक प्राप्त कर सकते हैं पर्याप्त जब UTF-8 अक्षम करने, खासकर जब ऐसा करने से बड़ी फ़ाइलें grepping प्रदर्शन में सुधारgrep -i
एड्रियन PRONK

7

यह एक वास्तविक उत्तर की तुलना में एक अतिरिक्त विश्लेषण है, लेकिन यह डेटा के प्रकार के आधार पर भिन्न होता है। सबसे पहले, एक बेस रीडिंग:

$ printf "%s\n" {1..1000000} > numbers.txt

$ time python sort.py <numbers.txt >s1.txt
real    0m0.521s
user    0m0.216s
sys     0m0.100s

$ time sort <numbers.txt >s2.txt
real    0m3.708s
user    0m4.908s
sys     0m0.156s

ठीक है, अजगर बहुत तेज है। हालाँकि, आप sortसंख्यात्मक रूप से क्रमबद्ध करने के लिए कहकर कोर्यूटिल्स को तेज़ कर सकते हैं :

$ time sort <numbers.txt >s2.txt 
real    0m3.743s
user    0m4.964s
sys     0m0.148s

$ time sort -n <numbers.txt >s2.txt 
real    0m0.733s
user    0m0.836s
sys     0m0.100s

यह बहुत तेज़ है लेकिन अजगर अभी भी एक व्यापक अंतर से जीतता है। अब, फिर से कोशिश करते हैं लेकिन 1M नंबरों की गैर-सॉर्ट की गई सूची के साथ:

$ sort -R numbers.txt > randomized.txt

$ time sort -n <randomized.txt >s2.txt 
real    0m1.493s
user    0m1.920s
sys     0m0.116s

$ time python sort.py <randomized.txt >s1.txt
real    0m2.652s
user    0m1.988s
sys     0m0.064s

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

$ tr -dc 'A-Za-z0-9' </dev/urandom | head -c1000000 | 
    sed 's/./&\n/g' > random.txt

$ time sort  <random.txt >s2.txt 
real    0m2.487s
user    0m3.480s
sys     0m0.128s

$ time python sort.py  <random.txt >s2.txt 
real    0m1.314s
user    0m0.744s
sys     0m0.068s

पायथन अभी भी कोरयूटिल्स को हराता है, लेकिन आपके प्रश्न में जो दिखाते हैं उससे बहुत कम अंतर से। हैरानी की बात है, शुद्ध वर्णमाला डेटा को देखते हुए यह अभी भी तेज है:

$ tr -dc 'A-Za-z' </dev/urandom | head -c1000000 |
    sed 's/./&\n/g' > letters.txt

$ time sort   <letters.txt >s2.txt 
real    0m2.561s
user    0m3.684s
sys     0m0.100s

$ time python sort.py <letters.txt >s1.txt
real    0m1.297s
user    0m0.744s
sys     0m0.064s

यह भी ध्यान रखना महत्वपूर्ण है कि दोनों एक ही क्रमबद्ध आउटपुट का उत्पादन नहीं करते हैं:

$ echo -e "A\nB\na\nb\n-" | sort -n
-
a
A
b
B

$ echo -e "A\nB\na\nb\n-" | python sort.py 
-
A
B
a
b

अजीब तरह से पर्याप्त, --buffer-sizeविकल्प मेरे परीक्षणों में बहुत (या किसी भी) अंतर बनाने के लिए प्रतीत नहीं हुआ। अंत में, संभवत: गोल्डिलॉक के उत्तर में उल्लिखित विभिन्न एल्गोरिदम के कारण, अजगर sortज्यादातर मामलों में तेज प्रतीत होता है , लेकिन संख्यात्मक जीएनयू sortइसे अनसोल्ड नंबर 1 पर धड़कता है ।


ओपी को शायद मूल कारण मिल गया है लेकिन पूर्णता के लिए, यहाँ एक अंतिम तुलना है:

$ time LC_ALL=C sort   <letters.txt >s2.txt 
real    0m0.280s
user    0m0.512s
sys     0m0.084s


$ time LC_ALL=C python sort.py   <letters.txt >s2.txt 
real    0m0.493s
user    0m0.448s
sys     0m0.044s

1 अधिक अजगर-फू के साथ किसी ने मुझे list.sort()छँटाई का परीक्षण करने की कोशिश करनी चाहिए उसी गति को निर्दिष्ट करके छँटाई विधि को प्राप्त किया जा सकता है।


5
आपके अंतिम नमूने के आधार पर पायथन सॉर्ट का एक अतिरिक्त गति लाभ है: ASCII संख्यात्मक क्रम। sortलगता है अपरकेस / लोअरकेस तुलना के लिए थोड़ा अतिरिक्त काम कर रहा है।
इज़काता

@ इज़्काता यही है! नीचे मेरा जवाब देखें।
21

1
दरअसल अजगर को कच्चे stdinइनपुट से बाहर अपने आंतरिक तारों का निर्माण करने में बहुत अधिक परेशानी होती है। नंबरों के लिए उन परिवर्तित ( lines = map(int, list(stdin))) और वापस ( stdout.writelines(map(str,lines))) बनाता पूरे छंटाई धीमी जाना, ऊपर 0.234s से मेरी मशीन पर 0.720s को असली।
एंथन

6

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

पायथन का सॉर्ट एक अद्वितीय हाइब्रिड मर्ज / सम्मिलन प्रकार, टाइमसॉर्ट का उपयोग करता है , जो ओ (एन) के सर्वोत्तम मामले परिदृश्य के साथ तुलना की एक चर संख्या करेगा - संभवतः, पहले से ही सॉर्ट की गई सूची पर - लेकिन आमतौर पर लॉगरिदमिक (तार्किक रूप से, आप सॉर्ट करते समय सामान्य मामले के लिए लॉगरिदमिक से बेहतर नहीं हो सकता है)।

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

तीन का एक कारक (या 3 से अधिक, जब sortसे समानांतर है) हालांकि थोड़ा सा है, जो मुझे आश्चर्यचकित करता है कि क्या यहां कोई आकस्मिकता नहीं है, जैसे कि sortडिस्क को स्वैप करना ( -Tविकल्प ऐसा लगता है कि यह करता है)। हालाँकि, आपका कम sys बनाम उपयोगकर्ता समय का तात्पर्य है कि यह समस्या नहीं है।


अच्छी बात यह है कि दोनों कार्यान्वयन सी में लिखे गए हैं। मुझे यकीन है कि अगर मैं अजगर में एक छँटाई एल्गोरिथ्म को लागू करता हूं तो यह बहुत, बहुत धीमा होगा।
20

वैसे, फ़ाइल में 0 और 1 के बीच बेतरतीब ढंग से उत्पन्न फ्लोट मान होते हैं, इसलिए शोषण करने के लिए बहुत अधिक संरचना नहीं होनी चाहिए।
अगुरार
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.