std::map build - Warum dauert das so lange?



  • volkard schrieb:

    4000 Befehle in einer Funktion müssen halt bestraft werden.

    Aber wie soll ich die map denn sonst initialisieren können? 4000 Befehle find ich jetzt auch nicht viel um ehrlich zu sein...

    volkard schrieb:

    Ist es schneller, wenn Du eine Schleife bis 4000 laufen läßt?

    Ja, dann läuft der Build-Vorgang innerhalb Sekundenbruchteilen, selbst wenn ich noch viel mehr Einträge erstelle. Problem ist aber dass ich keine Schleife verwenden kann, da die Einträge individuell und einzigartig sind.

    MFK schrieb:

    Kann ich nicht reproduzieren. Mit Visual C++ 2010 und 2012 dauern 4000 Zeilen nur wenige Sekunden.

    Vielleicht läuft da ein Plug-In Amok?

    Hm das ist seltsam. Habs extra an zwei komplett verschiedenen Rechnern getestet, auf beiden tritt das Problem auf...



  • happystudent schrieb:

    volkard schrieb:

    4000 Befehle in einer Funktion müssen halt bestraft werden.

    Aber wie soll ich die map denn sonst initialisieren können? 4000 Befehle find ich jetzt auch nicht viel um ehrlich zu sein...

    Array!



  • @happystudent
    Der Optimizer versucht die ganze Funktion zu optimieren.
    Wenn die 1000 Zeilen hat, von der jede Zeile ein Template instanziert, und die aufgerufenen Funktionen eindeutig Inlining-Kandidaten sind...
    Der Compiler hat da einfach viel zu viele Möglichkeiten wie er optimieren könnte. z.B. den Aufruf in der ersten Zeile inlinen, den in der zweiten nicht usw. - macht theoretisch 2^N Möglichkeiten (und das nur für eine der vielen Optimierungen die er machen kann).
    Die kann er natürlich bei N=1000 sowieso nicht alle untersuchen -- aber dass er sich mehr Zeit lässt je grösser die Funktion ist, finde ich nicht wirklich verwunderlich.

    => Dauert halt.

    Und?
    1000 solche Zeilen brauchst du netmal in generiertem Code. Generier dir ein static const Array wo die Daten drin sind und loop' da drüber.

    Bzw. wenns anders nicht geht, dann pack ein #pragma optimize() drumrum, mit dem du lokal die Optimierungen deaktivierst.



  • happystudent schrieb:

    Hm das ist seltsam. Habs extra an zwei komplett verschiedenen Rechnern getestet, auf beiden tritt das Problem auf...

    Es tritt nur auf, wenn Optimierungen eingeschaltet sind.

    Daher: Siehe hustbaer. Füll deine Map aus einem Array.



  • Ok, habs jetzt mit einem Array versucht. Damit geht es jetzt, Build-Zeit sind damit 25 Sekunden. Ist zwar immernoch recht viel aber erträglich, da man ja nicht so oft Release-Build macht.

    Danke auf jeden Fall 👍



  • Und bitte übergebe Referenzen.



  • Mr.Long schrieb:

    Und bitte übergebe Referenzen.

    Wo meinst du jetzt, im Konstruktor? Die strings müssen da doch eh kopiert werden, ist dass da nicht egal?

    Hab übrigens ein neues Problem mit der Array Technik. Und zwar ist folgendes extrem nervig:

    struct Data
    {
    	Data() {};
    	Data(int number_, std::string text1_, std::string text2_) : number(number_), text1(text1_), text2(text2_) {};
    
    	std::string text1;
    	std::string text2;
    	int number;
    };
    
    // Daten Array mit den 4000 Einträgen
    const int DATA_SIZE = 2;
    Data const data_array[] = { Data(0, "kurzer test string", "langer test string"),
    							Data(0, "kurzer test string", "langer test string") };
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    
    	std::map<std::string, Data> my_map;
    
    	for (unsigned int i = 0; i < DATA_SIZE; i++) {
    		my_map["?"] = data_array[i]; // <- Wie komm ich jetzt hier an den zugehörigen key?
    	}
    
    	return 0;
    }
    

    Zwar kann ich meine Daten jetzt in das const array reinschmeissen, allerdings hab ich dann ja nicht den benötigten key für die map zur Verfügung, da der Schlüssel nicht in der struct Data gespeichert werden soll.

    Einzige Lösung die mir bis jetzt einfällt um das zu lösen wäre ein zweites Array mit den keys mitzuschleifen. Das ist aber extrem nervig, da die Übersicht dann noch mehr leidet. Vor allem wenn man dann mal eine Zeile löschen/hinzufügen will muss man dann genau aufpassen dass man das alles manuell richtig macht.

    Daher ist ein zweites array wohl keine gute Lösung. Wie könnte man das sonst machen? Muss ja irgendwie möglich sein eine map vernünftig und ohne massiven manuellen Aufwand zu initialisieren?

    Da hätte ich auch gleich noch eine Frage. Die lange Build-Zeit bei Initialisierung ohne array resultiert wohl aus den 4000 Konstruktor-Aufrufen in der Funktion. Wenn ich keine eigene Datenstruktur einfüge sondern direkt strings ist die Build-Zeit sehr kurz - was macht die std::string Klasse hier anders dass deren Konstruktoren soviel effektiver gebuildet werden können?



  • std::pair<std::string, Data> const data_array[] = {
        std::pair<std::string, Data>("key1", Data(0, "kurzer test string", "langer test string")),
        std::pair<std::string, Data>("key2", Data(0, "kurzer test string", "langer test string")),
        // ...
        }; 
    
    size_t const data_size = sizeof(data_array)/sizeof(data_array[0]);
    
    int _tmain(int argc, _TCHAR* argv[]) 
    { 
        std::map<std::string, Data> my_map(&data_array[0], &data_array[data_size]); // <- Das wäre eine Möglichkeit
        return 0; 
    }
    
    // oder gleich so -----------------------V
    std::map<std::string, Data> const my_global_map(&data_array[0], &data_array[data_size]);
    

  • Mod

    Und warum soll das schneller sein. Ich finde es aleine schon problematisch wieviele Allocationen hier durchgeführt werden müssen.
    Bei Programmstart, dann nochmal muss das ganze Zeugs kopiert werden...

    Nimm z.B. Smart-Pointer und lass die Daten nur einmal erzeugen, was natürlich einen weitere indirekten Zugriff bedeutet, aber damit würden die Objekte nicht kopiert. Oder wenn das statisch ist arbeite mit const Zeigern.



  • Wie oft ändern sich denn die Einträge in die Maß?

    Wenn das relativ statisch ist, dann könnte man das Befüllen der Map auch in eine eigene Objektdatei packen und die nicht bei jeder kleinen Änderung am eigentlichen Programm neu kompiliert werden müsste.



  • Martin Richter schrieb:

    Und warum soll das schneller sein.

    Was ist in letzter Zeit immer mit den unpassenden "warum soll das {xxx} sein" Fragen 😕
    Ich hab' nie behauptet dass es "schneller" sein soll (schneller als was übrigens?).

    Die Frage war

    happystudent schrieb:

    Zwar kann ich meine Daten jetzt in das const array reinschmeissen, allerdings hab ich dann ja nicht den benötigten key für die map zur Verfügung, da der Schlüssel nicht in der struct Data gespeichert werden soll.

    Einzige Lösung die mir bis jetzt einfällt um das zu lösen wäre ein zweites Array mit den keys mitzuschleifen. Das ist aber extrem nervig, da die Übersicht dann noch mehr leidet. Vor allem wenn man dann mal eine Zeile löschen/hinzufügen will muss man dann genau aufpassen dass man das alles manuell richtig macht.

    Daher ist ein zweites array wohl keine gute Lösung. Wie könnte man das sonst machen? Muss ja irgendwie möglich sein eine map vernünftig und ohne massiven manuellen Aufwand zu initialisieren?



  • hustbaer schrieb:

    std::map<std::string, Data> my_map(&data_array[0], &data_array[data_size]); // <- Das wäre eine Möglichkeit
    

    Ah, das ist schon viel besser 👍

    Morle schrieb:

    Wie oft ändern sich denn die Einträge in die Maß?

    Wenn das relativ statisch ist, dann könnte man das Befüllen der Map auch in eine eigene Objektdatei packen und die nicht bei jeder kleinen Änderung am eigentlichen Programm neu kompiliert werden müsste.

    Die Einträge ändern sich eigentlich ziemlich selten. Macht es dann einen Unterschied ob man eine fertig kompilierte .cpp Datei hat (die ja beim kompilieren dann auch nicht mehr angefasst wird) oder eine eigene Objektdatei?

    Martin Richter schrieb:

    Und warum soll das schneller sein. Ich finde es aleine schon problematisch wieviele Allocationen hier durchgeführt werden müssen.
    Bei Programmstart, dann nochmal muss das ganze Zeugs kopiert werden...

    Ist der Compiler nicht schlau genug das selbst zu checken? Weil das Daten-Array würde ich nur lokal in der Funktion befüllen, die dann auch die map befüllt.

    EDIT: Hm, nach dem Verlagern der Initialisierung in eine eigene Funktion erhalte ich einen Stack-Overflow... Wenn ich das array global deklariere allerdings nicht. Wie kann das jetzt sein, ich will das Daten-Array ja nicht die Ganze Zeit im Speicher mitschleifen, daher würde ich es gerne lokal in einer extra Funktion haben dass es nach befüllen der map wieder freigegeben werden kann...


  • Mod

    Dein lokaler Heap ist eben begrenzt. Und Du schleppst dennoch den Code und den Speicher mit Dir rum. Spätestens in der EXE...



  • Ok, und was mache dann jetzt am besten? Kann ja nicht sein dass es so kompliziert ist eine map effizient zu befüllen...


  • Mod

    Nimm einen Statischen Array als POD.
    Verwende in der MAP nur const Zeiger auf diesen Array.



  • ...oder lies den Kram aus einer Datei ein. Kann ja nicht sein, dass diese 4000 Key-Value-Pairs so statisch sind, dass sie unbedingt in der exe sein müssen.

    MfG SideWinder


Anmelden zum Antworten