2012-12-11 14 views
13

मैं यह देखकर बहुत हैरान था कि जब आप --ignore-case विकल्प grep पर जोड़ते हैं तो यह 50x बार खोज को धीमा कर सकता है। मैंने इसे दो अलग-अलग मशीनों पर एक ही परिणाम के साथ परीक्षण किया है। मैं विशाल प्रदर्शन अंतर के लिए एक स्पष्टीकरण खोजने के लिए उत्सुक हूँ।"grep --ignore-case" 50 गुना धीमा क्यों है?

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

test.txt

yes all work and no play makes Jack a dull boy | head -c 50M > test.txt 
echo "Jack is no fun" >> test.txt 
echo "Jack is no Fun" >> test.txt 

प्रदर्शन बनाएं

नीचे धीमापन का प्रदर्शन है। --ignore-case विकल्प जोड़कर आदेश 57x गुना धीमा हो जाता है।

$ time grep fun test.txt 
all work and no plJack is no fun 
real 0m0.061s 

$ time grep --ignore-case fun test.txt 
all work and no plJack is no fun 
Jack is no Fun 
real 0m3.498s 

संभव स्पष्टीकरण

चारों ओर Googling मैं एक UTF-8 स्थान में धीमी गति से किया जा रहा है ग्रेप पर एक चर्चा पाया। तो मैंने निम्नलिखित परीक्षण चलाया, और यह तेज हो गया। मेरी मशीन पर डिफ़ॉल्ट लोकेल en_US.UTF-8 है, इसलिए इसे POSIX पर सेट करने के लिए एक प्रदर्शन बूट किया गया प्रतीत होता है, लेकिन अब निश्चित रूप से मैं यूनिकोड टेक्स्ट पर सही ढंग से खोज नहीं कर सकता जो अवांछित है। यह अभी भी 2.5 गुना धीमा है।

$ time LANG=POSIX grep --ignore-case fun test.txt 
all work and no plJack is no fun 
Jack is no Fun 
real 0m0.142s 

वैकल्पिक

हम पर्ल इस्तेमाल कर सकते हैं बजाय यह तेजी से अभी भी 5.5 गुना तेजी से तो केस संवेदी ग्रेप है, लेकिन। और उपरोक्त POSIX grep लगभग दोगुना तेज़ है।

$ time perl -ne '/fun/i && print' test.txt 
all work and no plJack is no fun 
Jack is no Fun 
real 0m0.388s 

तो मैं अगर कोई एक है एक तेजी से सही विकल्प और व्याख्या पढ़ सकते हैं अच्छा लगेगा।

अद्यतन - CentOS

दो मशीनों है कि दोनों के ऊपर परीक्षण किया गया उबंटू एक 11.04 (Natty Narwhal), अन्य 12.04 (सटीक छिपकली) चल रहे थे। CentOS 5.3 मशीन पर एक ही परीक्षण चलाने से निम्नलिखित दिलचस्प परिणाम मिलते हैं। दो मामलों के प्रदर्शन के परिणाम लगभग समान हैं। अब सेंटोस 5.3 जनवरी 200 9 में जारी किया गया था, एक grep 2.5.1 चला रहा है जबकि उबंटू 12.04 grep 2.10 चला रहा है। तो नए संस्करण में बदलाव और दो वितरण में मतभेद हो सकते हैं।

$ time grep fun test.txt 
Jack is no fun 
real 0m0.026s 

$ time grep --ignore-case fun test.txt 
Jack is no fun 
Jack is no Fun 
real 0m0.027s 

उत्तर

8

मुझे लगता है कि इस बग रिपोर्ट को समझने में मदद करता है क्यों यह धीमी है:

bug report grep, slow on ignore-case

+3

आप एक सारांश प्रदान कर सकते हैं? –

0

एक केस-संवेदी खोज करने के लिए, ग्रेप पहले है एक करने के लिए अपने पूरे 50   एमबी फ़ाइल को रूपांतरित करने मामला या दूसरा। इसमें समय लगेगा। इतना ही नहीं, लेकिन स्मृति प्रतियां हैं ...

अपने परीक्षण मामले में, आप पहले फ़ाइल उत्पन्न करते हैं।इसका मतलब है कि यह स्मृति कैश किया जाएगा। पहले grep रन केवल कैश किए गए पृष्ठों पर mmap है; इसे डिस्क तक पहुंच भी नहीं है।

केस-असंवेदनशील grep वही करता है, लेकिन फिर यह उस डेटा को संशोधित करने का प्रयास करता है। इसका अर्थ यह है कि कर्नेल प्रत्येक संशोधित 4   केबी पृष्ठ के लिए अपवाद लेगा, और एक ही समय में एक ही पृष्ठ में, एक नई पृष्ठ में पूरे 50   एमबी की प्रतिलिपि बनाने के लिए समाप्त हो जाएगा।

असल में, मैं धीमा होने की उम्मीद करता हूं। शायद 57x धीमी नहीं, लेकिन निश्चित रूप से धीमी है।

+0

मुझे नहीं लगता कि आप इसके बारे में सही हैं। यह फ़ाइल छोटी है, यह केवल 50 एमबी है। अधिक महत्वपूर्ण रूप से मेरे अपडेट को देखें, Centos लगभग एक ही निष्पादन समय पर दोनों खोजों को निष्पादित करता है। –

+0

50 एमबी 12500 मेमोरी पेज, ~ एमपी 3 के 50 मिनट, हॉटमेल अटैचमेंट सीमा 5 गुना है .... मुझे यकीन नहीं है कि मैं इसे "छोटा" कहूंगा। – ams

+0

वैसे भी, जैसे मैंने कहा। 57x धीमा थोड़ा अधिक लगता है। – ams

8

यह धीमापन grep (यूटीएफ -8 लोकेल पर) के कारण लगातार फाइलों "/ usr/lib/locale/locale-archive" और "/usr/lib/gconv/gconv-modules.cache" तक पहुंचता है।

इसे strace उपयोगिता का उपयोग करके दिखाया जा सकता है। दोनों फाइलें glibc से हैं।

+0

+1 –

0

कारण यह है कि इसे वर्तमान लोकेल के लिए यूनिकोड-जागरूक तुलना करने की आवश्यकता है, और मारत के उत्तर के आधार पर, यह ऐसा करने में बहुत सक्षम नहीं है।

यह दिखाता है कि बहुत तेजी से यह जब यूनिकोड पर ध्यान नहीं दिया जाता है:

$ time LC_CTYPE=C grep -i fun test.txt 
all work and no plJack is no fun 
Jack is no Fun 
real 0m0.192s 

बेशक, इस विकल्प ऐसे n/n, ँ/ओ के रूप में अन्य भाषाओं में पात्रों के साथ काम नहीं करेगा, Ð/ð, Æ/æ और इतने पर।

एक अन्य विकल्प इतना है कि यह मामला असंवेदनशीलता के साथ regex से मेल खाता संशोधित करने के लिए है:

$ time grep '[Ff][Uu][Nn]' test.txt 
all work and no plJack is no fun 
Jack is no Fun 
real 0m0.193s 

यह यथोचित तेज है, लेकिन निश्चित रूप से यह एक दर्द किसी कक्षा के प्रत्येक वर्ण परिवर्तित करने के लिए है, और यह करने के लिए आसान नहीं है इसे उपनाम के विपरीत, उपनाम या sh स्क्रिप्ट में परिवर्तित करें।

तुलना के लिए, अपने सिस्टम में:

$ time grep fun test.txt 
all work and no plJack is no fun 
real 0m0.085s 

$ time grep -i fun test.txt 
all work and no plJack is no fun 
Jack is no Fun 
real 0m3.810s