Programmlaufzeitfrage



  • Habe nämlich mal irgendwo gelesen, das sie c++string genauso schnell ist wie die Ansi string

    wenn dein C Freund die strings in C genau so dynamisch allocieren wuerde, dann ja ...

    Programmiertechnisch vergleichst du aepfel mit birnen ...
    Praktisch gesehen ist der vergleich natuerlich schon zulaessig, machen ja beide programme das selbe.
    Problem ist nur dass das C programm auf datentechnische gegebenheiten spezialisiert ist (1000000 zeilen maximal, max 25 zeichen pro zeile) das ist schon ne heftige Sache.

    Noch was. std::string wird beim allokieren niemals mit nem statischen array
    char staticString[256];
    konkurieren koennen. dazu isses auch ned gedacht.
    sondern es ist ne vereinfachung fuer sowas :

    char * pDynString = (char *)malloc(len);
    // irgend was machen
    free(pDynString);

    wenn du unter c++ auch feste groessen hasst, hindert dich keiner dran statische arrays zu verwenden. Wenn du die oefter allokierst, solltest du das auch ...

    wenn ich fuer "deine Aufgabenstellung" nen konkurrierentes programm schreiben sollt, wuerden da keine std::strings auftauchen und auch streams sind da nicht wirklich optimal.
    Ich wuerde genau so mit festen puffern, und wahrscheinlich in speicherbereich gemappte dateien (BS speziefisch), oder mit den filepuffern direkt arbeiten ...

    Ciao ...



  • Mit iostreams wirst du *nie* so schnell werden wie mit den "stdio" Funktionen von C. Eigentlich eine uralte Geschichte, sollte jeder wissen. iostreams sind IMHO sowieso der mieseste unnötigste Teil der ganzen C++ Standard Library.



  • Noch mal zum Thema C++ schnell oder nicht. Folgendes Programm macht auch nicht weniger als das des OP, benötigt aber für die angegebenen Datei mit 160000 Zeilen bei ca 25 Zeichen pro Zeile weniger als 0,6sec - inklusive Schreiben der neuen Datei.
    (Generiert mit VC++2005 Express - Release-Mode)

    #include <iostream>
    #include <string>
    #include <fstream>
    #include <iterator>
    #include <algorithm>
    #include <limits>
    
    struct DoppelZeile
    {
        friend std::istream& operator>>( std::istream& in, DoppelZeile& dz )
        {
            if( !getline( in, dz.m_zeile ).eof() )
                in.ignore( std::numeric_limits< std::streamsize >::max(), 
                    std::istream::traits_type::to_int_type( '\n' ) );
            return in;
        }
        friend std::ostream& operator<<( std::ostream& out, const DoppelZeile& dz )
        {
            return out << dz.m_zeile << std::endl;
        }
    private:
        std::string m_zeile;
    
    };
    
    int main()
    {
        using namespace std;
        ifstream in("input.txt");
        ofstream out("output.txt");
        copy( istream_iterator< DoppelZeile >( in ), istream_iterator< DoppelZeile >(),
            ostream_iterator< DoppelZeile >( out ) );
        return 0;
    }
    

    Wobei mir nicht ganz klar ist, ob jetzt jede gerade oder jede ungerade Zeile gelesen werden soll.

    Plotzenhotz schrieb:

    Mit iostreams wirst du *nie* so schnell werden wie mit den "stdio" Funktionen von C.

    dafür gibt es keinen technischen Grund. Vorausgesetzt man vergleicht gleiche Funktionalitäten, was hier nicht ganz einfach ist, wie wir ja schon gesehen haben.

    Ansonsten stimme ich mit HumeSikkins überein. Da hängt einiges von der Implementierung in der STL ab ... und auch von einer schnellen Platte 😉 .

    Gruß
    Werner



  • Dynamische Speicheranforderungen und eine überaus komplizierte (dafür natürlich auch mächtige) Library vs. keine dynamischen Speicheranforderungen und eine relativ einfache Library sind also kein technischer Grund?

    Mir auch egal, es bleibt die Tatsache dass auch mit MSVC 2005 (SP1 BETA) im Release Mode und natürlich mit 'Link Time Code Generation' an die iostreams Variante gegenüber der stdio Variante ganz gewaltig abstinkt. Probiers selbst wenn dus nicht glaubst:

    #define _WIN32_WINNT 0x0501
    
    #include <stdlib.h>
    #include <stdio.h>
    #include <conio.h>
    #include <time.h>
    #include <windows.h>
    #include <mmsystem.h>
    #undef min
    #undef max
    #include <iostream> 
    #include <string> 
    #include <fstream> 
    #include <iterator> 
    #include <algorithm> 
    #include <limits> 
    
    #pragma comment(lib, "winmm")
    
    static const char* g_inputFileName = "c:\\in.txt";
    static const char* g_outputFileName = "c:\\out.txt";
    
    static const size_t gc_lineCount = 160*1000;
    
    void CreateTestFile()
    {
        FILE* outFile = fopen(g_inputFileName, "w");
        if(!outFile)
    		abort();
    
    	for(size_t i = 0; i < gc_lineCount; i++)
    	{
    		int r = rand() % 3;
    		char const* s = 0;
    		switch(r)
    		{
    		case 0: s = "Bla, Bloe\n"; break;
    		case 1: s = "Ding, Dong\n"; break;
    		case 2: s = "X, Y\n"; break;
    		}
    
    		fputs(s, outFile);
    	}
    
    	fclose(outFile);
    }
    
    void ReadInputFile()
    {
        FILE* inFile = fopen(g_inputFileName, "r");
        if(!inFile)
    		abort();
    
    	char buffer[1024];
    	while(fgets(buffer, sizeof(buffer), inFile))
    		;
    
    	fclose(inFile);
    }
    
    size_t TestStdio()
    {
        FILE* inFile = fopen(g_inputFileName, "r");
        if(!inFile)
    		abort();
    
        FILE* outFile = fopen(g_outputFileName, "w");
        if(!outFile)
    		abort();
    
    	size_t outLines = 0;
    
    	char buffer[1024];
    	while(1)
    	{
    		if(!fgets(buffer, sizeof(buffer), inFile))
    			break;
    		if(!fgets(buffer, sizeof(buffer), inFile))
    			break;
    
    		if(fputs(buffer, outFile) < 0)
    			abort();
    
    		outLines++;
    	}
    
    	fclose(inFile);
    	fclose(outFile);
    
    	return outLines;
    }
    
    struct DoppelZeile 
    { 
        friend std::istream& operator>>( std::istream& in, DoppelZeile& dz ) 
        { 
            in.ignore(std::numeric_limits<std::streamsize>::max(), std::istream::traits_type::to_int_type('\n')); 
            getline(in, dz.m_zeile);
            return in; 
        } 
        friend std::ostream& operator<<( std::ostream& out, const DoppelZeile& dz ) 
        { 
            return out << dz.m_zeile << std::endl; 
        } 
    private: 
        std::string m_zeile; 
    
    }; 
    
    size_t TestIostream1() 
    { 
    	std::ifstream in(g_inputFileName);
    	std::ofstream out(g_outputFileName);
    	std::copy(std::istream_iterator<DoppelZeile>(in), std::istream_iterator<DoppelZeile>(),
    		std::ostream_iterator<DoppelZeile>(out));
    	return 0;
    }
    
    size_t TestIostream2() 
    { 
    	std::ifstream in(g_inputFileName);
    	std::ofstream out(g_outputFileName);
    
    	std::string str;
    	str.reserve(1024);
    
    	size_t outLines = 0;
    
    	while(in.good())
    	{
    		in.ignore(std::numeric_limits<std::streamsize>::max(), std::istream::traits_type::to_int_type('\n'));
    		if(std::getline(in, str).eof())
    			break;
    		out << str << std::endl;
    		outLines++;
    	}
    
    	return outLines;
    }
    
    int main(int argc, char** argv)
    {
    	CreateTestFile();
    
    	if(::timeBeginPeriod(1) != TIMERR_NOERROR)
    		abort();
    
    	size_t outLineCount = 0;
    	DWORD t0, t1;
    
    	// TestStdio
    	for(unsigned rep = 0; rep < 5; rep++)
    	{
    		::DeleteFileA(g_outputFileName);
    		ReadInputFile();
    		ReadInputFile();
    		printf("TestStdio...\n");
    		t0 = ::timeGetTime();
    		outLineCount = TestStdio();
    		t1 = ::timeGetTime();
    		printf("Lines: %ld, time: %ld msec\n", long(outLineCount), long(t1 - t0));
    	}
    
    	// TestIostream1
    	for(unsigned rep = 0; rep < 5; rep++)
    	{
    		::DeleteFileA(g_outputFileName);
    		ReadInputFile();
    		ReadInputFile();
    		printf("TestIostream1...\n");
    		t0 = ::timeGetTime();
    		outLineCount = TestIostream1();
    		t1 = ::timeGetTime();
    		printf("Lines: %ld, time: %ld msec\n", long(outLineCount), long(t1 - t0));
    	}
    
    	// TestIostream2
    	for(unsigned rep = 0; rep < 5; rep++)
    	{
    		::DeleteFileA(g_outputFileName);
    		ReadInputFile();
    		ReadInputFile();
    		printf("TestIostream2...\n");
    		t0 = ::timeGetTime();
    		outLineCount = TestIostream2();
    		t1 = ::timeGetTime();
    		printf("Lines: %ld, time: %ld msec\n", long(outLineCount), long(t1 - t0));
    	}
    
    	::timeEndPeriod(1);
    
    	printf("\nPress any key to continue.\n");
    	getch();
    
    	return 0;
    }
    

    Ergebnis:

    TestStdio...
    Lines: 80000, time: 84 msec
    TestStdio...
    Lines: 80000, time: 108 msec
    TestStdio...
    Lines: 80000, time: 84 msec
    TestStdio...
    Lines: 80000, time: 83 msec
    TestStdio...
    Lines: 80000, time: 87 msec
    TestIostream1...
    Lines: 0, time: 702 msec
    TestIostream1...
    Lines: 0, time: 705 msec
    TestIostream1...
    Lines: 0, time: 692 msec
    TestIostream1...
    Lines: 0, time: 712 msec
    TestIostream1...
    Lines: 0, time: 717 msec
    TestIostream2...
    Lines: 80000, time: 701 msec
    TestIostream2...
    Lines: 80000, time: 690 msec
    TestIostream2...
    Lines: 80000, time: 693 msec
    TestIostream2...
    Lines: 80000, time: 692 msec
    TestIostream2...
    Lines: 80000, time: 707 msec
    
    Press any key to continue.
    

    Das ist Faktor 8 (jeweils schnellste Zeiten).

    p.S.: noch kürzere Zeilen zu verwenden (1 Zeichen/Zeile, und mit "str.reserve(1024);" auskommentiert) so dass die small-string Optimierung vom MSVC 2005 auch sicher greift macht im übrigen keinen Unterschied. Längere Zeilen (400~500 Zeichen) helfen sehr den Unterschied drastisch zu verkleinern, schneller bleibt trotzdem die stdio Variante.



  • Plotzenhotz schrieb:

    Dynamische Speicheranforderungen und eine überaus komplizierte (dafür natürlich auch mächtige) Library vs. keine dynamischen Speicheranforderungen und eine relativ einfache Library sind also kein technischer Grund?

    doch.
    und genau deswegen misst du mist.
    benutz doch mal <fstream> ohne <string>. das tut nämlich auch gehen.



  • @volkard: Na dann werd ich das wohl probieren. Wollen wir wetten dass iostream trotzdem langsamer bleibt als stdio?



  • p.S.: @volkard: ich wollte eigentlich auch nur die "0,6 Sekunden" von "Werner Salomon" etwas relativieren - er hat ja den Vergleich mit stdio nicht angestellt, diesen habe ich jetzt nachgeholt -- um zu zeigen dass seine 0,6 Sekunden bloss wenig klingen weil der OP anscheinend einen sehr langsamen PC hat 🙂



  • Plotzenhotz schrieb:

    Wollen wir wetten dass iostream trotzdem langsamer bleibt als stdio?

    Klar. Es handelt sich ja auch um eine extrem dynamische Bibliothek, die objektorientiert implementiert ist, mit dem gesamten damit verbundenen Overhead (virtuelle Funktionen).

    Als Resultat erhält man ein ungemein mächtiges und nützliches Werkzeug, das quasi beliebig erweitert werden kann. Das mit stdio zu vergleichen ist in jedem Fall unsinnig.



  • Meine Ergebnisse:
    Jeweils 100000 Zeilen a 25 Zeichen lesen und jede zweite Zeile in neue Datei schreiben.
    (VC++ 8.0 release-build Pentium 4)

    #include <iostream>
    #include <fstream> 
    #include <string> 
    #include <time.h> 
    #include <conio.h> 
    
    using namespace std; 
    
    int main () 
    {   // VARIANTE 1 C++
        clock_t start=0, finish=0; 
        string text,text2, muell; 
    
        start = clock();  
    
        ifstream indatei("c:\\EINLAUF.TXT");  
        ofstream outdatei("c:\\EINLAUFXXX.TXT"); 
    
        if(indatei) 
            while(getline(indatei, text2)) 
            { 
                    text += text2;
                    text += "\n";
                    getline(indatei,muell); 
            } 
    
        outdatei << text; 
    
        finish = clock();     
        indatei.close();
        outdatei.close();
        cout  << "VARIANTE 1 C++ " << endl
         << "Rechenzeit C++ -Code : " << (double)(finish - start) << " ms" << endl << endl; 
    
    //*****************************************************************        
    
    #define IN_DATEI "c:\\EINLAUF.TXT" 
    #define OUT_DATEI "c:\\EINLAUFXXX.TXT" 
    #define N 25            // Vektorlänge der Char-Felder 
    #define ABBR 1000000    // max. Schleifenlänge für Not-Abbruch 
    
        FILE *fptr1; 
        FILE *fptr2; 
        unsigned long is = 0; 
        char input[N], dummy[N]; 
        start=0, finish=0; 
    
        fptr1 = fopen(IN_DATEI, "r");    // Datei mit Werten 
        fptr2 = fopen(OUT_DATEI, "w");    // Ergebnisdatei mit halbierter Auflösung 
    
        if (!fptr1) 
            printf("Fehler beim Oeffnen der Input-Datei!\n"); 
        else 
        { 
            start = clock();    // 1. Wert für Rechenzeitbestimmung 
    
            while (fgets(dummy,    N, fptr1) != NULL)    // jedes Wertepaar mit ungeradem Index wird ignoriert 
            { 
                fgets(input, N, fptr1);    // jedes Wertepaar mit geradem Index wird gespeichert 
                fprintf(fptr2, "%s", input); 
                is++;    
                if (is>=ABBR) 
                    break;    // Notausstieg aus while-Schleife bei einer best. max. Zeilenzahl 
            } 
    
            finish = clock();    // 2. Wert für Rechenzeitbestimmung 
            _fcloseall();     
            printf ("VARIANTE 2 C-Code\n");
            printf("Anzahl der Wertepaare vorher: %lu\n", is*2); 
            printf("Anzahl der Wertepaare jetzt: %lu\n", is); 
            printf("Rechenzeit C-Code : %.0f ms\n\n", (double)(finish - start)); 
            //printf("CPS:  %f\n\n", (float)CLOCKS_PER_SEC); 
        } 
    //*******************************************************************************
    //Letzer Versuch C++
        start = clock();
        ofstream aus;
        aus.open("c:\\EINLAUFXXX.TXT", ios_base::out | ios_base::binary| ios_base::trunc);
        ifstream ein;
        ein.open("c:\\EINLAUF.TXT", ios_base::in | ios_base::binary| ios_base::ate);
        char* zBuf;
        int len = ein.tellg();
        if (zBuf = new char [len])
        {
          ein.seekg(ios::beg);
          ein.read(zBuf, len);
        }
        else return -1;
    
        char* p = zBuf, *p2, *p3;
        size_t a, s = 0;
        int i = 0;
        for (int toggle = 0 ; i < len; ++i)
        {
            if (zBuf[i] == 10)
            {
                toggle ^= 1;        
                if (toggle)
                {
                    p2 = &zBuf[i+1];         
                    continue;
                }
                else
                {
                    p3 = &zBuf[i+1];     
                    a = p3-p2;
                    memcpy(p, p2, a);
                    p += a, s += a;
                }
            }
        }
        if (zBuf[i] != 10)
        {
            p3 = &zBuf[i], a = p3-p2;
            memcpy(p, p2, a);
            p += a, s += a;
        }
        aus.write(zBuf, (streamsize)s);
    
        finish = clock();
        cout    << "VARIANTE 3 C++ ohne std::string" << endl
                << "Rechenzeit C/C++ Code : " << (double)(finish - start) << " ms" << endl << endl; 
        ein.close();
        aus.close();
        delete[] zBuf;
        return 0;
    }
    

    Ausgabe:

    VARIANTE 1 C++
    Rechenzeit C++ -Code : 203 ms

    VARIANTE 2 C-Code
    Anzahl der Wertepaare vorher: 100000
    Anzahl der Wertepaare jetzt: 50000
    Rechenzeit C-Code : 109 ms

    VARIANTE 3 C++ ohne std::string
    Rechenzeit C/C++ Code : 31 ms



  • So. Ich hab den Test mit "in.getline(buffer, sizeof(buffer))" gemacht (also ganz ohne std::string - womit wir nun endlich genau die selbe Funktionalität verglichen hätten), der ist nun statt Faktor 8.3 etwa Faktor 7.5 langsamer.

    BTW: dass die "ios_base::binary und alles auf einmal lesen" Variante schnell ist ist klar, die verwendet ja auch die iostreams Library für nix anderes als einen grossen Block Daten zu kopieren. Das bringt man mit stdio genauso hin, und sicher auch wieder schneller, wenn auch wahrscheinlich bloss um ein paar Takte.

    @Konrad Rudolph: ich hab auch von Anfang an behauptet dass iostreams langsamer sein wird als stdio (lies ein paar Postings weiter oben). Bloss kam dann so ein "dafür gibt es garkeinen Grund" Kommentar. Ob es einen Grund gibt hin oder her, auf jeden Fall ist es so, und ich sah mich genötigt das zu demonstrieren.



  • Plotzenhotz schrieb:

    So. Ich hab den Test mit "in.getline(buffer, sizeof(buffer))" gemacht (also ganz ohne std::string - womit wir nun endlich genau die selbe Funktionalität verglichen hätten), der ist nun statt Faktor 8.3 etwa Faktor 7.5 langsamer.

    das ist immernoch unfug.
    zeig mal dein endgültiges programm, das unter fairen bedingungen <cstdio> mit <fstream> vergleicht und faktor 7.5 schneller ist. ich gebe mir ausnahmsweise die mühe, es zu verreißen, da du mir in anderen threads deutlich als ahnunghaber und hilfsbereiter aufgefallen bist.



  • Das ganze vergleichen hier ist doch Bullshit Leute !
    Und auch noch Faktoren rausgeben wollen, was die clib schneller ist wie eine IOStream impl?

    Jeder der mit streams arbeitet, weiss das er es ned wegen der geschwindigkeit tut. Wenn man sagt das c++ performant sein kann/soll, meint man in c++ auch so programmieren kann, das die geringfuegig geringere performance kein Grund sein soll die anderen vorteile von c++, der stl und dem stream konzept ueber boartd zu werfen !

    Und wenn ich wirklich auf speed aus bin bei dateioperationen ( Bitte welchem vernunftigen Programmierer intressiert nen minimaler performanceverlust bei dateioperationen auf nem multhithreading/multiprocessing BS ??? ) aus bin, werd ich doch zuerst mein BS konsultieren (Posix, winapi) und die streams / filebuffer bei seite legen ...

    Ciao ...



  • ich lass jetzt mal das hier dorchlaufen:

    #include <iostream>
    #include <cstdio>
    #include <fstream>
    #include <string>
    using namespace std;
    
    #define g_inputFileName "test.txt"
    #define gc_lineCount 100000000
    
    void CreateTestFile()
    {
        FILE* outFile = fopen(g_inputFileName, "w");
        if(!outFile)
            abort();
    
        for(size_t i = 0; i < gc_lineCount; i++)
        {
            int r = rand() % 3;
            char const* s = 0;
            switch(r)
            {
            case 0: s = "Bla, Bloe\n"; break;
            case 1: s = "Ding, Dong\n"; break;
            case 2: s = "X, Y\n"; break;
            }
    
            fputs(s, outFile);
        }
    
        fclose(outFile);
    }
    
    int countLineNumbers1(){
    	int result=0;
    	FILE* inFile = fopen(g_inputFileName, "r");
    	if(!inFile)
    		abort();
    	char buffer[1024];
    	while(fgets(buffer, sizeof(buffer), inFile))
    		++result;
    	fclose(inFile);
    	return result;
    }
    
    int countLineNumbers2(){
    	int result=0;
    	ifstream inFile(g_inputFileName);//edit: hier war fehlerhaft ios::binary
    	if(!inFile)
    		throw 4711;
    	char buffer[1024];
    	while(inFile.getline(buffer,1024))
    		++result;
    	return result;
    }
    
    int countLineNumbers3(){
    	int result=0;
    	ifstream inFile(g_inputFileName,ios::binary);
    	if(!inFile)
    		throw 4711;
    	string buffer;
    	while(getline(inFile,buffer))
    		++result;
    	return result;
    }
    
    int main()
    {
    	CreateTestFile();
    	for(int i=0;i<10;++i)
    	{
    		{
    			clock_t start=clock();
    			cout<<1<<' '<<countLineNumbers1()<<' ';
    			cout<<(clock()-start)/double(CLOCKS_PER_SEC)<<endl;
    		}
    		{
    			clock_t start=clock();
    			cout<<2<<' '<<countLineNumbers2()<<' ';
    			cout<<(clock()-start)/double(CLOCKS_PER_SEC)<<endl;
    		}
    		{
    			clock_t start=clock();
    			cout<<3<<' '<<countLineNumbers3()<<' ';
    			cout<<(clock()-start)/double(CLOCKS_PER_SEC)<<endl;
    		}
    	}
    	return 0;
    }
    

    das zählt einfach nur die zeilen einer ca 1G großen (einstellbar) datei.

    ausgabe:

    1 100000000 19.906
    2 100000000 19.734
    3 100000000 36.516
    1 100000000 19.765
    2 100000000 19.735
    3 100000000 36.703
    1 100000000 19.75
    2 100000000 19.875
    3 100000000 36.469
    1 100000000 19.75
    2 100000000 19.968
    3 100000000 36.313
    1 100000000 19.859
    2 100000000 19.672
    3 100000000 36.188
    

    ich denke mal, an dem ergebnis gibts wenig zu interpretieren. string ist lahm. fstream und iostream sind gleich schnell.



  • @volkard
    Welchen Compiler bzw. welche Standard-Lib verwendest du? Erhalte mit dem VC 8 andere Ergebnisse:

    1 10000000 1.922
    2 10000000 5.734
    3 10000000 7.891
    1 10000000 1.906
    2 10000000 5.687
    3 10000000 7.891
    [...]
    

    Dateigröße war ca. 100 MB.



  • Plotzenhotz schrieb:

    So. Ich hab den Test mit "in.getline(buffer, sizeof(buffer))" gemacht (also ganz ohne std::string - womit wir nun endlich genau die selbe Funktionalität verglichen hätten), der ist nun statt Faktor 8.3 etwa Faktor 7.5 langsamer.

    die selbe funktionalität reicht aber nicht. wenn man wie Helmut S. die c-variante einigermaßen annehmbar implementiert aber die c++-variante wie der letzte gamecoder vergurkt, ist der vergleich nicht fair.

    ich hab auch nicht gerafft, warum man für

    //so oder so ähnlich war's doch
    while(in.getline(file,buffer))&&in.getline(file,buffer))
       out.write(buffer);
    

    ein mords brimboriom (unübersichtlich, unnötig, lahm) mit ner klasse namens doppelzeile machen muss.



  • HumeSikkins schrieb:

    @volkard
    Welchen Compiler bzw. welche Standard-Lib verwendest du? Erhalte mit dem VC 8 andere Ergebnisse:

    MinGW

    D:\source\filetest>g++ -v
    Reading specs from C:/MinGW/bin/../lib/gcc/mingw32/3.4.2/specs
    Configured with: ../gcc/configure --with-gcc --with-gnu-ld --with-gnu-as --host=
    mingw32 --target=mingw32 --prefix=/mingw --enable-threads --disable-nls --enable
    -languages=c,c++,f77,ada,objc,java --disable-win32-registry --disable-shared --e
    nable-sjlj-exceptions --enable-libgcj --disable-java-awt --without-x --enable-ja
    va-gc=boehm --disable-libgcj-debug --enable-interpreter --enable-hash-synchroniz
    ation --enable-libstdcxx-debug
    Thread model: win32
    gcc version 3.4.2 (mingw-special)
    
    1 10000000 1.922
    2 10000000 5.734
    3 10000000 7.891
    1 10000000 1.906
    2 10000000 5.687
    3 10000000 7.891
    [...]
    

    Dateigröße war ca. 100 MB.

    jo, dann ist die ms-lib wiedermal buggy.
    hab jetzt auch mit ms gemessen.

    1 100000000 25.219
    2 100000000 52.703
    3 100000000 67.984
    


  • Hat noch jemand einen älteren VC installiert? Mich würde mal interessieren, wie die nicht-standard-IOStreams abschneiden. Also <iostream.h> und <fstream.h> statt
    <iostream> und <fstream>.



  • das ist immernoch unfug.
    zeig mal dein endgültiges programm, das unter fairen bedingungen <cstdio> mit <fstream> vergleicht und faktor 7.5 schneller ist. ich gebe mir ausnahmsweise die mühe, es zu verreißen, da du mir in anderen threads deutlich als ahnunghaber und hilfsbereiter aufgefallen bist.

    Mein endgültiges Programm zeig ich heut' Abend her, sitz grad noch in der Arbeit. Ich bitte nur meine Postings in diesem Thread im Kontext zu sehen, die "Doppelzeile" Sache z.B. stammt nicht von mir, hab ich nur übernommen um zu zeigen dass die auch nicht schneller ist als die "einfache" (normale) Variante. Da ich mich mit iostreams noch nicht SO angefreundet habe wusste ich auch schlichtweg nicht dass getline() mit char* Buffer verfügbar ist, daher hab ich nen std::string genommen. Egal. Meine Erfahrung ist dass iostreams deutlich langsamer sind, so ziemlich egal was man macht. Mag daran liegen dass die MSVC Variante mies implementiert ist. Wie gesagt später mehr.

    Und eine Frage gleich vorweg: wie bitte ist "ios::binary" mit fopen(..., "r") zu vergleichen fair? Wenn dann bitte "ios::binary" mit fopen(..., "rb") vergleichen, sonst brauchen wir über fair gleich garnicht zu sprechen. Dass es auf UNIX systemen keinen Unterschied macht ist mir dabei egal, bei MSVC z.B. macht es einen Unterschied. Da es hier aber um Textfiles geht denke ich sollten wir beim "r" und ohne "ios::binary" bleiben. Auf jeden Fall entweder beide binary oder beide als Text Stream.



  • Plotzenhotz schrieb:

    Und eine Frage gleich vorweg: wie bitte ist "ios::binary" mit fopen(..., "r") zu vergleichen fair?

    ups, das war noch aus versehen drin. hab allerlei verstellt und probiert, um rauszufinden, wie ihr auf die lahmen ergebnisse kommt. ios::binary gehört da nicht rein und macht aber auch keinen unterschied, hoffe ich.

    edit: doch, macht anscheinend deutlichen unterschied. muss ich heut abend ausmessen.



  • @volkard:
    So. Forum geht wieder (was warn da los?). Gut.
    Hab mich nu noch etwas rumgespielt und ein paar kleine Fallstricke für die iostreams entfernt. u.a. das "std::endl" durch '\n' ersetzt und zurück zu MSVC 7.1 da die meiste Zeit bei der MSVC 8 Version beim locking/unlocking diverser critical sections draufgegangen ist (mehrmals pro "getline" Aufruf - daher auch die wüst groben Unterschiede zur stdio Version). Und MSVC 8 hat leider keine single threaded runtime mehr. Neuer Code:

    #define _WIN32_WINNT 0x0501
    
    #include <windows.h>
    #include <mmsystem.h>
    #undef min
    #undef max
    
    #include <stdlib.h>
    #include <stdio.h>
    #include <conio.h>
    #include <time.h>
    #include <iostream> 
    #include <fstream>
    
    #pragma comment(lib, "winmm")
    
    static const char* const gc_inputFileName = "c:\\in.txt";
    static const char* const gc_outputFileName = "c:\\out.txt";
    static const size_t gc_lineCount = 160*1000;
    
    void CreateTestFile()
    {
    	FILE* outFile = fopen(gc_inputFileName, "w");
    	if(!outFile)
    		abort();
    
    	for(size_t i = 0; i < gc_lineCount; i++)
    		fputs("123456789012345678901234\n", outFile);
    
    	fclose(outFile);
    }
    
    void ReadInputFileStdio()
    {
    	FILE* inFile = fopen(gc_inputFileName, "r");
    	if(!inFile)
    		abort();
    
    	char buffer[1024];
    	while(fgets(buffer, sizeof(buffer), inFile))
    		;
    
    	fclose(inFile);
    }
    
    void ReadInputFileIostream()
    {
    	std::ifstream in(gc_inputFileName);
    	char buffer[1024];
    	while(in.good())
    		in.getline(buffer, sizeof(buffer));
    }
    
    size_t TestStdio()
    {
    	FILE* inFile = fopen(gc_inputFileName, "r");
    	if(!inFile)
    		abort();
    
    	FILE* outFile = fopen(gc_outputFileName, "w");
    	if(!outFile)
    		abort();
    
    	size_t outLines = 0;
    
    	char buffer[1024];
    	while(1)
    	{
    		if(!fgets(buffer, sizeof(buffer), inFile))
    			break;
    		if(!fgets(buffer, sizeof(buffer), inFile))
    			break;
    
    		if(fputs(buffer, outFile) < 0)
    			abort();
    
    		outLines++;
    	}
    
    	fclose(inFile);
    	fclose(outFile);
    
    	return outLines;
    }
    
    size_t TestIostream3() 
    { 
    	std::ifstream in(gc_inputFileName);
    	std::ofstream out(gc_outputFileName);
    
    	char buffer[1024];
    
    	size_t outLines = 0;
    
    	while(1)
    	{
    		if(!in.getline(buffer, sizeof(buffer)))
    			break;
    		if(!in.getline(buffer, sizeof(buffer)))
    			break;
    
    		out << buffer << '\n';
    		outLines++;
    	}
    
    	return outLines;
    }
    
    int main(int argc, char** argv)
    {
    	CreateTestFile();
    
    	if(::timeBeginPeriod(1) != TIMERR_NOERROR)
    		abort();
    
    	size_t outLineCount = 0;
    	DWORD t0, t1;
    
    	// TestStdio
    	for(unsigned rep = 0; rep < 5; rep++)
    	{
    		::DeleteFileA(gc_outputFileName);
    		ReadInputFileStdio();
    		ReadInputFileStdio();
    		printf("TestStdio: ");
    		t0 = ::timeGetTime();
    		outLineCount = TestStdio();
    		t1 = ::timeGetTime();
    		printf("Lines: %ld, time: %ld msec\n", long(outLineCount), long(t1 - t0));
    	}
    
    	// TestIostream3
    	for(unsigned rep = 0; rep < 5; rep++)
    	{
    		::DeleteFileA(gc_outputFileName);
    		ReadInputFileIostream();
    		ReadInputFileIostream();
    		printf("TestIostream3: ");
    		t0 = ::timeGetTime();
    		outLineCount = TestIostream3();
    		t1 = ::timeGetTime();
    		printf("Lines: %ld, time: %ld msec\n", long(outLineCount), long(t1 - t0));
    	}
    
    	::timeEndPeriod(1);
    
    	printf("\nPress any key to continue.\n");
    	getch();
    }
    

    Ergebnis (Pentium 4 Northwood, 2.8GHz, XP SP2):

    TestStdio: Lines: 80000, time: 66 msec
    TestStdio: Lines: 80000, time: 66 msec
    TestStdio: Lines: 80000, time: 66 msec
    TestStdio: Lines: 80000, time: 66 msec
    TestStdio: Lines: 80000, time: 67 msec
    TestIostream3: Lines: 80000, time: 111 msec
    TestIostream3: Lines: 80000, time: 105 msec
    TestIostream3: Lines: 80000, time: 107 msec
    TestIostream3: Lines: 80000, time: 108 msec
    TestIostream3: Lines: 80000, time: 112 msec
    
    Press any key to continue.
    

    Nu ham wir 66 vs. 105 msec.
    Ohne output:

    TestStdio: Lines: 80000, time: 34 msec
    TestStdio: Lines: 80000, time: 32 msec
    TestStdio: Lines: 80000, time: 33 msec
    TestStdio: Lines: 80000, time: 32 msec
    TestStdio: Lines: 80000, time: 45 msec
    TestIostream3: Lines: 80000, time: 71 msec
    TestIostream3: Lines: 80000, time: 70 msec
    TestIostream3: Lines: 80000, time: 69 msec
    TestIostream3: Lines: 80000, time: 69 msec
    TestIostream3: Lines: 80000, time: 90 msec
    
    Press any key to continue.
    

    Also 32 vs. 69 msec. Viel besser als mit MSVC 8, aber iostreams immer noch langsamer. Falls ich da jetzt immer noch nen "Fehler" (eine "Bremse") in der iostream Implementierung drin habe bitte gerne mich darauf hinzuweisen.

    "Selber Code" mit MSVC6, <iostream.h> und <fstream.h> (std:: entfernt, die liegen beim MSVC 6 im global namespace, und "rep" vor den Schleifen definiert, weil MSVC 6 for-scope-bug, sonst keine Änderung). Optimiert für Pentium-Pro, inlining aktiviert, single-threaded Runtime, ... . R/W:

    TestStdio: Lines: 80000, time: 72 msec
    TestStdio: Lines: 80000, time: 70 msec
    TestStdio: Lines: 80000, time: 68 msec
    TestStdio: Lines: 80000, time: 69 msec
    TestStdio: Lines: 80000, time: 69 msec
    TestIostream4: Lines: 80000, time: 191 msec
    TestIostream4: Lines: 80000, time: 174 msec
    TestIostream4: Lines: 80000, time: 184 msec
    TestIostream4: Lines: 80000, time: 172 msec
    TestIostream4: Lines: 80000, time: 175 msec
    
    Press any key to continue.
    

    R:

    TestStdio: Lines: 80000, time: 34 msec
    TestStdio: Lines: 80000, time: 34 msec
    TestStdio: Lines: 80000, time: 34 msec
    TestStdio: Lines: 80000, time: 32 msec
    TestStdio: Lines: 80000, time: 32 msec
    TestIostream4: Lines: 80000, time: 126 msec
    TestIostream4: Lines: 80000, time: 202 msec
    TestIostream4: Lines: 80000, time: 128 msec
    TestIostream4: Lines: 80000, time: 124 msec
    TestIostream4: Lines: 80000, time: 123 msec
    
    Press any key to continue.
    

    Andere Compiler hab ich leider keine, STLPORT auch nicht, wäre aber interessant wie schnell die ist.
    Und... hast du mit oder ohne MT Support compiliert? Würe mich nur interessieren.


Anmelden zum Antworten