2011-10-24 11 views
7

मैं C++ (ASCII में 1Go से अधिक) में फ़ाइल में एक विशाल सरणी लिखने का सबसे प्रभावी तरीका खोजने के लिए कुछ मानक चला रहा था।fprintf बनाम std :: ofstream के बहुत आश्चर्यजनक perfs (fprintf बहुत धीमा है)

तो मैं std :: fprintf साथ ofstream (स्विच मैं नीचे इस्तेमाल किया देखना)

case 0: { 
     std::ofstream out(title, std::ios::out | std::ios::trunc); 
     if (out) { 
      ok = true; 
      for (i=0; i<M; i++) { 
       for (j=0; j<N; j++) { 
        out<<A[i][j]<<" "; 
       } 
       out<<"\n"; 
      } 
      out.close(); 
     } else { 
      std::cout<<"Error with file : "<<title<<"\n"; 
     } 
     break; 
    } 
    case 1: { 
     FILE *out = fopen(title.c_str(), "w"); 
     if (out!=NULL) { 
      ok = true; 
      for (i=0; i<M; i++) { 
       for (j=0; j<N; j++) { 
        fprintf(out, "%d ", A[i][j]); 
       } 
       fprintf(out, "\n"); 
      } 
      fclose(out); 
     } else { 
      std::cout<<"Error with file : "<<title<<"\n"; 
     } 
     break; 
    } 

तुलना में और मेरी बड़ी समस्या यह है कि fprintf std :: ofstream की तुलना में अधिक 12x धीमी है thant हो रहा है है। क्या आपको पता है कि मेरे कोड में समस्या की उत्पत्ति क्या है? या शायद std :: ऑफस्ट्रीम fprintf की तुलना में बहुत अनुकूलित है?

:

आपको बहुत बहुत धन्यवाद (और एक अन्य सवाल आप एक और तेज़ तरीका एक फाइल लिखने के लिए पता है)

(विस्तार: मैं के साथ जी ++ -Wall -O3 संकलन किया गया था)

+0

मुझे लगता है कि आपको अधिक समान व्यवहार प्राप्त करने के लिए fprintf के बजाय fputs का उपयोग करना चाहिए –

+1

'ostream :: लिखें()': http://www.cplusplus.com/reference/iostream/ostream/write/ – Nim

+1

@ एंडर्सके .: नहीं। फ़ुटपुट एक स्ट्रीमबफ (अनफॉर्मेटेड) के बराबर है; fprintf ostream का उचित समकक्ष है। – MSalters

उत्तर

15

fprintf("%d" प्रति पूर्णांक के बाद प्रारूप स्ट्रिंग के रनटाइम पार्सिंग की आवश्यकता होती है। एक संकलन के बाद, ostream& operator<<(ostream&, int) संकलक द्वारा हल किया जाता है।

1

क्या आपने सिंक_with_stdio को आपके द्वारा दिखाए गए कोड के कहीं ऊपर की ओर सेट किया है?

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

4

ठीक है, fprintf() रनटाइम पर थोड़ा और काम करना है, क्योंकि इसे प्रारूप स्ट्रिंग को पार्स और संसाधित करना है। हालांकि, आपकी आउटपुट फ़ाइल का आकार दिया गया है, मैं उम्मीद करता हूं कि उन मतभेदों का थोड़ा नतीजा होगा, और उम्मीद है कि कोड I/O बाध्य होगा।

इसलिए मुझे संदेह है कि आपका बेंचमार्क किसी तरह से त्रुटिपूर्ण है।

  1. यदि आप बार-बार परीक्षण चलाते हैं तो क्या आपको लगातार 12x अंतर मिलता है?
  2. यदि आप उस आदेश को उलट देते हैं जिसमें आप परीक्षण चलाते हैं तो समय के साथ क्या होता है?
  3. क्या होता है यदि आप अंत में fsync()/sync() पर कॉल करते हैं?
2

ऑफ़स्ट्रीम में एक फ़ाइल बफर है, यह डिस्क तक पहुंचने के समय को कम कर सकता है। इसके अलावा, fprintf चर पैरामीटर के साथ एक फ़ंक्शन है जो कुछ va_ # फ़ंक्शंस को कॉल करेगा, लेकिन ऑफस्ट्रीम जीता नहीं। मुझे लगता है कि आप परीक्षण करने के लिए fwrite() या putc() का उपयोग कर सकते हैं।

+0

पुट धीमा हो जाएगा क्योंकि यह केवल एक वर्ण लिखता है, यह धीमा हो जाएगा। –

1

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

class FastIntegerWriter 
{ 
private: 

    const int bufferSize; 
    int offset; 
    int file; 
    char* buffer; 

public: 

    FastIntegerWriter(int bufferSize = 4096); 
    int Open(const char *filename); 
    void Close(); 
    virtual ~FastIntegerWriter(); 
    void Flush(); 
    void Writeline(int value); 
}; 

#ifdef _MSC_VER 
# include <io.h> 
# define open _open 
# define write _write 
# define read _read 
# define close _close 
#else 
# include <unistd.h> 
#endif 
#include <fcntl.h> 

FastIntegerWriter::FastIntegerWriter(int bufferSize) : 
    bufferSize(bufferSize), 
    buffer(new char[bufferSize]), 
    offset(0), 
    file(0) 
{ 
} 

int FastIntegerWriter::Open(const char* filename) 
{ 
    this->Close(); 
    if (filename != NULL) 
     this->file = open(filename, O_WRONLY | O_CREAT | O_TRUNC); 
    return this->file; 
} 

void FastIntegerWriter::Close() 
{ 
    this->Flush(); 
    if (this->file > 0) 
    { 
     close(this->file); 
     this->file = 0; 
    } 
} 

FastIntegerWriter::~FastIntegerWriter() 
{ 
    this->Close(); 
    delete[] this->buffer; 
} 

void FastIntegerWriter::Flush() 
{ 
    if (this->offset != 0) 
    { 
     write(this->file, this->buffer, this->offset); 
     this->offset = 0; 
    } 
} 

void FastIntegerWriter::Writeline(int value) 
{ 
    if (this->offset >= this->bufferSize - 12) 
    { 
     this->Flush(); 
    } 

    // Compute number of required digits 

    char* output = this->buffer + this->offset; 

    if (value < 0) 
    { 
     if (value == -2147483648) 
     { 
      // Special case, the minimum integer does not have a corresponding positive value. 
      // We use an hard coded string and copy it directly to the buffer. 
      // (Thanks to Eugene Ryabtsev for the suggestion). 

      static const char s[] = "-2147483648\n"; 
      for (int i = 0; i < 12; ++i) 
       output[i] = s[i]; 
      this->offset += 12; 
      return; 
     } 

     *output = '-'; 
     ++output; 
     ++this->offset; 
     value = -value; 
    } 

    // Compute number of digits (log base 10(value) + 1) 

    int digits = 
     (value >= 1000000000) ? 10 : (value >= 100000000) ? 9 : (value >= 10000000) ? 8 : 
     (value >= 1000000) ? 7 : (value >= 100000) ? 6 : (value >= 10000) ? 5 : 
     (value >= 1000) ? 4 : (value >= 100) ? 3 : (value >= 10) ? 2 : 1; 

    // Convert number to string 

    output[digits] = '\n'; 
    for (int i = digits - 1; i >= 0; --i) 
    { 
     output[i] = value % 10 + '0'; 
     value /= 10; 
    } 

    this->offset += digits + 1; 
} 

मुझे लगता है कि यह हर दूसरे विधि एक ascii फ़ाइल पर लिखने में बेहतर प्रदर्शन करेगी :) आप कुछ और प्रदर्शन का उपयोग कर प्राप्त कर सकते हैं:

अपने में फ़ाइल शामिल विंडोज़ निम्न स्तर apis WriteFile और ReadFile, लेकिन यह प्रयास के लायक नहीं है।

इसका इस्तेमाल करने के लिए ...

int main() 
{ 
    FastIntegerWriter fw; 
    fw.Open("test.txt"); 

    for (int i = -2000; i < 1000000; ++i) 
     fw.Writeline(i); 

    return 0; 
} 

आप किसी भी फ़ाइल निर्दिष्ट नहीं करते हैं यह मानक आउटपुट (कंसोल) का उपयोग करता है।

+1

ध्यान दें कि 'value = -value' गलत तरीके से काम करेगा यदि सबसे नकारात्मक पूर्णांक पास किया गया है क्योंकि कोई सकारात्मक सकारात्मक मान नहीं है। Http://stackoverflow.com/a/5165813/1353187 –

+0

सही देखें। उस कोड को लिखने के बारे में नहीं सोचा था। इसे संभालने का सबसे अच्छा और सरल तरीका एक स्ट्रिंग में हार्ड कोड को सबसे नकारात्मक पूर्णांक है और अगर (value == most_negative_integer) write_the_string लिखना है –

संबंधित मुद्दे