कुछ ऐसा चाहिए जो "wc -l" से तेज हो


12

1GB की तरह एक बहुत बड़ी फ़ाइल के wc -lलिए धीमी गति से होता है। क्या हमारे पास किसी विशेष फ़ाइल के लिए नई संख्या की गणना करने का एक तेज़ तरीका है?


25
तेजी से डिस्क खरीदें? यह देखते हुए कि इनपुट के प्रत्येक बाइट का निरीक्षण इसके 0x0Aनिराकरण के लिए किया जाना चाहिए , आई / ओ नि: संदेह अड़चन है।
थ्रिग

2
यदि आपको wcबहुत अधिक ओवरहेड होने का संदेह है तो आप अपने स्वयं के कार्यान्वयन की कोशिश कर सकते हैं foreach byte in file: if byte == '\n': linecount++। यदि C या असेंबलर में लागू किया जाता है, तो मुझे नहीं लगता कि यह किसी भी तेजी से मिलेगा, शायद RTOS पर कर्नेल स्पेस में सर्वोच्च प्राथमिकता के साथ (या इसके लिए एक रुकावट का उपयोग करें - आप सिस्टम के साथ और कुछ नहीं कर सकते। .. सब ठीक है, मैं पछतावा ;-))
मर्फी

3
और बस एक पैमाने के लिए एक महसूस करने के लिए मैंने time wc -l some_movie.aviएक अनकैप्ड फ़ाइल पर एक त्वरित किया, जिसके परिणामस्वरूप 5172672 some_movie.avi -- real 0m57.768s -- user 0m0.255s -- sys 0m0.863s। जो मूल रूप से @thrig सही साबित होता है, मैं / O इस मामले में आपके प्रदर्शन को तोड़ देता है।
मर्फी

10
यह दिखाने का सबसे अच्छा तरीका है कि यह एक डिस्क IO टोंटी है, time wc -l some_large_file_smaller_than_cacheदो बार त्वरित उत्तराधिकार में करें और देखें कि दूसरा ऑपरेशन कितना तेज़ है, फिर time wc -l some_large_file_larger_than_cacheदेखें और देखें कि रन के बीच समय कैसे नहीं बदलता है। यहां ~ 280MB फ़ाइल के लिए, समय 1.7 सेकंड से 0.2 सेकंड तक चला जाता है, लेकिन 2GB फ़ाइल के लिए यह दोनों समय 14 सेकंड है।
आठबेटोनी

1
आपके लिए कितना धीमा है? क्या /usr/bin/time wc -l <file>कहता है? आपका हार्डवेयर क्या है? यदि आप बार-बार कमांड चलाते हैं तो क्या यह तेज है? हमें वास्तव में अधिक जानकारी की आवश्यकता है;)
२:१६

जवाबों:


21

आप C में लिखने का प्रयास कर सकते हैं :

#include <unistd.h>
#include <stdio.h>
#include <string.h>
int main(){
  char buf[BUFSIZ];
  int nread;
  size_t nfound=0;
  while((nread=read(0, buf, BUFSIZ))>0){
    char const* p;
    for(p=buf; p=memchr(p,'\n',nread-(p-buf)); nfound++,p++) {;}
  }
  if(nread<0) { perror("Error"); return 1; }
  printf("%lu\n", nfound);
  return 0;
}

wcl.cउदाहरण के लिए, साथ में संकलित करें gcc wcl.c -O2 -o wclऔर साथ में सहेजें

<yourFile ./wcl

यह मेरे सिस्टम पर 1GB फ़ाइल में लगभग 370ms (बार-बार रन) में छिड़के गए नए समाचार पाता है । (बफर का आकार बढ़ने से समय थोड़ा बढ़ जाता है, जिसकी उम्मीद की जानी है - BUFSIZ को इष्टतम के करीब होना चाहिए)। यह ~ 380ms मैं से मिल रहा है के लिए बहुत तुलनीय है wc -l

मैमपिंग मुझे लगभग 280ms का एक बेहतर समय देता है , लेकिन निश्चित रूप से यह वास्तविक फ़ाइलों (कोई FIFOS, कोई टर्मिनल इनपुट, आदि) तक सीमित होने की सीमा नहीं है:

#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
int main(){
  struct stat sbuf;
  if(fstat(0, &sbuf)<0){ perror("Can't stat stdin"); return 1; }

  char* buf = mmap(NULL, sbuf.st_size, PROT_READ, MAP_PRIVATE, 0/*stdin*/, 0/*offset*/);
  if(buf == MAP_FAILED){ perror("Mmap error"); return 1; } 

  size_t nread = sbuf.st_size, nfound=0;
  char const* p;
  for(p=buf; p=memchr(p,'\n',nread-(p-buf)); nfound++,p++) {;}

  printf("%lu\n", nfound);
  return 0;
}

मैंने अपनी परीक्षण फ़ाइल इसके साथ बनाई:

 $ dd if=/dev/zero of=file bs=1M count=1042 

और इसके साथ कुछ नई परीक्षाएँ जोड़ीं:

 $ echo >> 1GB 

और एक हेक्स संपादक।


मैं मिमीप परिणाम टीबीएच पर हैरान था। मुझे लगता है कि पढ़ने या लिखने की तुलना में mmaping तेज था, लेकिन फिर मैंने कुछ लिनक्स बेंचमार्क देखे जो इसके विपरीत थे। ऐसा लगता है कि यह इस मामले में बहुत सच है।
PSkocik

4
mmap को linux पर काफी बेहतर परिणाम मिलने वाले हैं क्योंकि यह इन दिनों विशाल पृष्ठों पर मैप करेगा, और TLB misses sloooowwwwwww हैं।
jthill

फ़ाइल के विभिन्न भागों को अलग-अलग थ्रेड्स में (जैसे कि एक OpenMP forलूप के साथ) पढ़ने में कुछ लाभ हो सकता है ताकि कुछ प्रगति हो सके, जबकि एक थ्रेड इनपुट के इंतजार में रुका हुआ है। लेकिन दूसरी ओर, यह I / O शेड्यूलिंग में बाधा डाल सकता है, इसलिए मैं जो भी सिफारिश कर सकता हूं, वह इसे करने की कोशिश करना है, और मापना है!
स्पाइट

read()संस्करण पढ़ने के आगे से लाभ हो सकता।
बरमार

1
@TobySpeight हाँ, मल्टीथ्रेडिंग इसे गति प्रदान कर सकता है। 2 ^ 16 लुक अप टेबल के माध्यम से एक बार में दो बाइट्स को स्कैन करने की तलाश में, पिछली बार जब मैं इसके साथ खेला था, तो बहुत अच्छी गति प्रदान की।
पीएसकोकिक

18

आप कॉल की संख्या को कम करके @pskocik द्वारा सुझाए गए समाधान पर सुधार कर सकते हैं read। वहाँ एक हैं बहुत कुछ कॉल की पढ़ने के लिए BUFSIZएक 1GB फ़ाइल से हिस्सा। ऐसा करने के लिए सामान्य दृष्टिकोण बफर आकार को बढ़ाकर है:

  • बस मज़े के लिए, 10. या 100 के एक कारक द्वारा बफर-आकार को बढ़ाने का प्रयास करें। मेरे डेबियन 7 पर, BUFSIZ8192 है। मूल कार्यक्रम के साथ, यह 120 हजार रीड ऑपरेशंस है। आप शायद 100 के कारक से कम करने के लिए 1Mb इनपुट बफर खरीद सकते हैं।
  • अधिक इष्टतम दृष्टिकोण के लिए, अनुप्रयोग एक बफर को फाइल के रूप में बड़े रूप में आवंटित कर सकते हैं, जिसके लिए एक एकल रीड ऑपरेशन की आवश्यकता होती है। यह "छोटी" फ़ाइलों के लिए पर्याप्त रूप से काम करता है (हालांकि कुछ पाठकों की मशीन पर 1Gb से अधिक है)।
  • अंत में, आप मेमोरी-मैपेड I / O के साथ प्रयोग कर सकते हैं, जो आवंटन को इस तरह से संभालता है।

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

यही बात mmapएक FAQ में शामिल करने के लिए मेरी टू-डू सूची पर (दूसरे मामले में भी लागू होती है , एक डेवलपर ने ऐसे परिदृश्य में बहुत अच्छे परिणाम की सूचना दी जहां डिस्क कैश में सुधार का वास्तविक कारण था)। बेंचमार्क विकसित करने से अच्छे (या बुरे) प्रदर्शन के कारणों का विश्लेषण करने में समय लगता है।

आगे की पढाई:


2
आप एक निश्चित सीमा से ऊपर बफर आकारों के प्रभाव को कम कर रहे हैं। आमतौर पर, 4KB-ish से परे बफर साइज बढ़ाने से बहुत मदद नहीं मिलती है, और वास्तव में हानिकारक हो सकता है क्योंकि यह बफर को L1 कैश से बाहर धकेल सकता है। मेरी मशीन पर, dd1MB बफ़र्स का उपयोग करके परीक्षण 8KB से धीमा है। Wc के लिए 8KB डिफ़ॉल्ट मान वास्तव में बहुत अच्छी तरह से चुना गया है, यह सिस्टम की एक बड़ी रेंज के लिए इष्टतम के करीब होगा।
11 दिसंबर को मार्सेल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.