Wc इतना धीमा क्यों है?


17

Wc उपयोगिता इतनी धीमी क्यों है?

जब मैं इसे एक बड़ी फ़ाइल पर चलाता हूं, तो इसे md5sum से लगभग 20 गुना अधिक समय लगता है:

MyDesktop:/tmp$ dd if=/dev/zero bs=1024k count=1024 of=/tmp/bigfile
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 0.687094 s, 1.6 GB/s

MyDesktop:/tmp$ time wc /tmp/bigfile 
         0          0 1073741824 /tmp/bigfile

real    0m45.969s
user    0m45.424s
sys     0m0.424s

MyDesktop:/tmp$ time md5sum /tmp/bigfile 
cd573cfaace07e7949bc0c46028904ff  /tmp/bigfile

real    0m2.520s
user    0m2.196s
sys     0m0.316s

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

(यह उबंटू 13.04, 64 बिट पर है)


उन लोगों के लिए ध्यान दें, जो केवल लाइन काउंट की परवाह करते हैं: wc -l <filename> बहुत बड़ी फाइलों पर ज्यादा तेज है।
ईएल

जवाबों:


27

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

दरअसल, अगर मैं अपने लोकल LANGवेरिएबल को डिफॉल्ट से बदल देता हूं en_US.UTF-8(UTF-8 एक मल्टीबाइट कैरेक्टर सेट है) और इसे " C" (सिंपल सिंगल बाइट कैरेक्टर सेट) पर सेट करता है, wcसिंगल-बाइट ऑप्टिमाइज़ेशन का उपयोग करने में सक्षम है, जो इसे काफी तेजी से गति देता है। पहले की तुलना में केवल एक चौथाई ही लेना।

इसके अतिरिक्त, इसे केवल प्रत्येक वर्ण को जांचना होगा यदि यह शब्द ( -w), पंक्ति की लंबाई ( -L) या वर्ण ( -m) की गणना करता है। यदि यह केवल बाइट और / या लाइन काउंट कर रहा है, तो यह वाइड कैरेक्टर हैंडलिंग को छोड़ सकता है और फिर यह बहुत तेज़ी से - से तेज़ चलता है md5sum

मैं इसे से होकर गुजरता था gprof, और कार्यों कि multibyte वर्ण (को संभालने के लिए उपयोग किया जाता है mymbsinit(), mymbrtowc(), myiswprint(), आदि) निष्पादन समय अकेले का 30%, और कोड के बारे में ले रहे हैं कि बफर से तीसरे चरण का और अधिक जटिल है क्योंकि यह करने के लिए किया है चर आकार वर्णों के लिए बफर के माध्यम से चर आकार के चरणों को संभालें, साथ ही साथ आंशिक रूप से पूर्ण किए गए वर्णों को भराई करें जो बफर को बफर की शुरुआत में वापस फैलाते हैं ताकि अगली बार इसे संभाला जा सके।

अब जब मुझे पता है कि मुझे क्या देखना है, तो मुझे कुछ उपयोगिताओं के साथ utf-8 मंदी का उल्लेख करते हुए कुछ पोस्ट मिले:

/programming/13913014/grepping-a-huge-file-80gb-any-way-to-speed-it-up http://dtrace.org/blogs/brendan/2011/12/08 / 2000x प्रदर्शन-जीत /


2
ओह, एहसास हुआ कि आप ओपी हैं। : पी
इवान चाऊ

2
यद्यपि यह सबसे उत्कीर्ण उत्तर है, यह अप्रासंगिक है। md5sumकभी भी आपको शब्द संख्या की गणना करने की अनुमति नहीं देगा और wcफ़ाइल के md5 हैश की गणना नहीं करेगा! यह पूछना पसंद है कि टेक्स्ट लिखते समय मेरी कार मेरे टाइपराइटर की तुलना में इतनी धीमी क्यों है।
user49468

5
@ user49468: यह मान लेना उचित है कि दोनों IO- बद्ध हैं, क्योंकि दोनों को इनपुट फ़ाइल के प्रत्येक बाइट को पढ़ना है। यह उत्तर साबित करता है कि wcवास्तव में बहु-बाइट वर्णों को संसाधित करते समय सीपीयू-बाउंड है।
एमएसल्टर्स

2
@ user49468: wc और md5sum अलग-अलग काम कर सकते हैं, लेकिन दोनों एक फ़ाइल को पढ़ते हैं और एक अपेक्षाकृत सरल गणना करते हैं, एक चेकसम की गणना करता है, एक बाइट्स, शब्द विभाजक और newlines की गणना करता है। ठीक है, मुझे लगा कि यह सरल है, लेकिन मल्टीबीट कैरेक्टर सेट की अतिरिक्त जटिलता में तथ्य नहीं था। यह पूछना अधिक पसंद है "मेरी मिनीवैन की तुलना में स्टोर पर जाने में मेरी कार 20 गुना तेज क्यों है?" आप दोनों के बीच कुछ अंतर की उम्मीद करेंगे, लेकिन 20X अंतर नहीं।
जॉनी

1
@ जॉनी आप कार / मिनीवैन तुलना में इस पहलू का अभाव है कि दोनों को स्टोर में ले जाने के लिए डिज़ाइन किया गया है। तो एक गति की तुलना जगह में है। अपनी कार की तुलना स्ट्राइप पेंटिंग वाहन से करना अधिक उपयुक्त है। सिर्फ इसलिए कि दोनों सड़कों का उपयोग करते हैं उनकी गति प्रासंगिक नहीं है क्योंकि स्ट्रिप पेंटर खरीदारी और इसके विपरीत जाने के लिए अनुकूल नहीं है।
user49468

1

बस एक अनुमान है लेकिन आप संतरे की तुलना सेब की तुलना wcमें कर रहे हैं, जो कर रहा है बनाम क्या md5sumकर रहा है।

md5sum का कार्य

जब md5sumकिसी फाइल को प्रोसेस करता है तो वह फाइल को एक स्ट्रीम के रूप में खोलता है और फिर MD5 चेकसम फ़ंक्शन के माध्यम से स्ट्रीम को रन करना शुरू कर देता है जिसमें बहुत कम मेमोरी की आवश्यकता होती है। यह अनिवार्य रूप से सीपीयू और डिस्क I / O बाध्य है।

wc का कार्य

जब wcयह चलता है तो यह बहुत अधिक होता है, बस एक बार में एक चरित्र को फ़ाइल करना। इसमें वास्तव में फ़ाइल की संरचना का विश्लेषण करना है, एक समय में यह निर्धारित करना है कि पात्रों के बीच की सीमाएँ क्या हैं और यह एक शब्द सीमा है या नहीं।

उदाहरण

निम्नलिखित स्ट्रिंग्स के बारे में सोचें और प्रत्येक एल्गोरिदम को उनके माध्यम से आगे बढ़ना होगा क्योंकि वे उन्हें पार्स करते हैं:

“Hello! Greg”
“Hello!Greg”
“Hello\nGreg”
“A.D.D.”
“Wow, how great!”
“wow     \n\n\n    great”
“it was a man-eating shark.”

एमडी 5 के लिए, यह एक समय में इन स्ट्रिंग्स को एक चरित्र के माध्यम से बदल देता है। इसके लिए wcयह तय करना होगा कि एक शब्द और लाइन सीमा क्या है और इसे होने वाली घटनाओं की संख्या पर नज़र रखें।

अतिरिक्त wc चर्चा

मुझे यह कोडिंग चुनौती 2006 से मिली wcजो .NET में लागू करने की चर्चा करता है । मुश्किलें बहुत स्पष्ट हैं क्योंकि आप कुछ छद्म कोड देखते हैं, इसलिए यह wcअन्य कार्यों की तुलना में इतना धीमा क्यों प्रतीत होता है , इस पर प्रकाश डालना शुरू कर सकता है।


1
आप मानक यूनिक्स wc कमांड की तुलना में कुछ अलग का वर्णन कर रहे हैं (कम से कम, वह नहीं जो उबंटू के साथ आता है)। Wc अद्वितीय शब्दों की गिनती नहीं करता है , सिर्फ शब्द, इसलिए "हैलो हैलो वर्ल्ड" 3 शब्द हैं, न कि 2.
जॉनी

इस सिद्धांत के आधार पर यह एक सरल कार्य की तरह लगता है, जैसे कि लाइनें गिनना, अधिक तेज़ी से जाएगा। क्या एक पंक्ति गणना को निर्दिष्ट करने के लिए 'wc' को बदलना परिणामों को काफी हद तक संशोधित करता है? 'wc -l'
जोशुआ मिलर

@ जॉनी - मैंने कभी नहीं कहा कि यह आपके द्वारा कहा गया अनोखा शब्द है। wcफ़ाइल को पार्स करने के साथ ही कई चीजों को गिना जाता है। यह शब्द और लाइनों की संख्या को गिनता है, क्योंकि यह फ़ाइल को पार्स करता है। मैन पेज पढ़ें!
स्लम

@JoshuaMiller - अस्पष्ट है कि क्या wcकेवल लाइनों को गिनना ही आंतरिक सीमा है, ताकि यह केवल इन चीजों को गिना जाए या केवल लाइनों के परिणामों की रिपोर्ट करता है, भले ही यह अभी भी सब कुछ गिना हो।
स्लम

@ एसएलएम आपने कहा था कि यह अद्वितीय शब्दों को गिनता है, आपका उदाहरण कहता है "हैलो! ग्रेग ”का परिणाम हैलो 1, ग्रेग 1 , अर्थात प्रत्येक शब्द के लिए गिना जाता है। और .Net परियोजना जिसे आपने कहा है, "इसका एक मुख्य कार्य डेटा के एक सेट से गुजरना है और किसी दिए गए शब्द की पुनरावृत्ति की संख्या की गणना करना है। उदाहरण के लिए" हैलो, हाँ हैलो "यह वाक्य आपको बताएगा। हैलो शब्द का इस्तेमाल दो बार किया गया था और हां शब्द का इस्तेमाल एक बार किया गया था। ” जबकि वास्तव में गूंज का परिणाम "हैलो, हाँ हैलो" | wc - पासवर्ड , "3" है, न कि "हैलो: 2, हां: 1"
जॉनी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.