vector<string> initialisieren.. -> string==/!=string langsamer als strcmp()??
-
Don Carsto schrieb:
Tja, mit der boost Lösung das gleiche Problem.
Nach Verlassen der Funktion ein Ausnahmefehler.Wahrscheinlich rufst Du irgendwo undefiniertes Verhalten hervor.
Don Carsto schrieb:
Nur meldet mir der Compiler diesmal, daß er einen nicht-virtuellen Destruktor hat.
Wer hat einen nicht-virtuellen Destruktur und warum sollte das hier eine Rolle spielen?
Don Carsto schrieb:
Gehe ich recht in der Annahme, daß der vector am Ende nicht freigegeben werden kann und deswegen diesen Ausnahmefehler erzeugt?
Falsch geraten.
Versuche das Programm zu verkürzen und vereinfachen und damit den Fehler zu isolieren. Oft findet man so schon den Übeltäter. Wenn Du uns ein kurzes, komplettes Programm zeigen kannst, was sich Deiner Meinung nach ähnlich komisch verhält, dann kann man mehr dazu sagen. Betonung liegt auf "kurz" und "komplett".
-
SeppJ schrieb:
Dies wäre äußerst ungewöhnlich. Zeig mal mehr Code. Das mit dem fehlenden virtuellen Destruktor klingt schon einmal verdächtig. Erbst du etwa von einem STL-Container?
Ich habe nun mal das Ganze in eine einfache Consolen Anwendung gepackt. Die Warnungen mit dem non-virtuell-destruktor kommen trotzdem, aber es läuft ohne Ausnahme durch. (Die Warnungen kommen schon,wenn ich nur die boost-include einbinde) Liegt wohl eher an der hohen Warnstufe des Compilers.
Nun habe ich mal den "fehlerhaften" Code komplett gekürzt und schwupps läuft es durch.
Da scheint irgendein anderes böses Objekt die Ausnahme zu erzeugen.Leider ist der Coee so lang und komplex, daß ein posten nicht viel Sinn macht.
Da ich nun weiß, daß es nicht am vector selbst liegt, sondern eher an dem chaotischen Drumherum, werde ich das mal entwirren (Schritt für Schritt ausblenden) und die fehlerhafte Stelle suchen.
Sinn des Ganzen war sowieso zunächst den Code komplett zu Überarbeiten, um unsichere Stellen auszumerzen.
zu krümelkacker: (Post erst während der Erstellung gelesen)
Ja, leider kann ich keinen vereinfachten Code posten, der sich ähnlich verhält.
Und das mit dem Isolieren habe ich gerade in Angriff genommen. Mal sehen.Jedenfalls funktioniert die boost-Lösung und auch die GCC 4.5 mit dem noch nicht freigegebenen C++ Standard auch. Der Übeltäter ist irgendwo anders im Code.

Vielen Dank nochmal für die Unterstützung. Und die Lösung des Problems.
So.. nun gehts ans Fehlersuchen...

Gruß,
DC
-
So, habe die letzten Stunden damit verbracht den Fehler zu suchen.
Es lag an einem zu kleinen char filestring[40];
Dieses wurde wohl etwas zu weit (um 3 Zeichen) überschrieben.
Dadurch wurde die restliche Speicherverwaltung überaus brüchig.
Hatte sich bisher noch nie bemerkbar gemacht, doch seit ich nun auf std::strings und std::vector umgestellt habe, wurden Ausnahmen geschmissen.Eine tickende Zeitbombe....
-
Ich hoffe mal schwer, du hast nun das
char[]-Array durchstd::stringersetzt und nicht nur um 3 Zeichen vergrössert...
Wechsle bei der Gelegenheit am besten alle rohen C-Arrays aus (gegen
std::tr1::array,boost::array, oderstd::array- alles das Gleiche) und ersetze alle Zeiger auf dynamische Arrays durchstd::vector.
-
Ja, bin dabei, den kompletten Code zu überarbeiten.
Das war ja auch Sinn der Übung, daß ich die char Arrays durch std:string ersetzen wollte, a) um zu gucken, ob es dann eine Performance-Erhöhung gibt und b) weil ich std::string sicherer von der Speicherverwaltung halte.
Nebenher wollte ich dann auch gleich alle mehrdimensionalen char Arrays durch vector<string> ersetzen.Habe nun erstmal eine einigermassen lauffähige Version erschaffen, die sich nun genauso verhält wie die Alte, außer, daß es nun 3x-langsamer geworden ist.
Habe aber auch noch nicht den kompletten Code umgebastelt.
Sind noch einge Krücken drinne.
-
Don Carsto schrieb:
Habe nun erstmal eine einigermassen lauffähige Version erschaffen, die sich nun genauso verhält wie die Alte, außer, daß es nun 3x-langsamer geworden ist.
Sollte nicht sein, wenn man richtig umbaut.
Natürlich sollte man schon einige Dinge beachten, damit der Vergleich überhaupt gerechtfertigt ist:
- Ganze Container so selten wie möglich kopieren. Lieber mit Const-Referenzen oder Iteratoren arbeiten.
- Generell Objekt-Kopien vermeiden durch Einsatz von
swap()und Move-Semantik in C++0x. - Wenn die Grösse bei
std::vectorundstd::stringim Voraus bekannt ist, mitreserve()vorallokieren. - Im Release-Modus kompilieren und Debug-Laufzeitumgebung abschalten.
- Sicherheitsmassnahmen wie Checked-Iterators deaktivieren.
-
So, habe nun die Bremse gefunden.
Sehr kurios.Hatte zunächst nach dem Umstellen auf string und vector folgendes sehr zeitaufwendige Konstrukt von char-Array auf string umgestellt (Dieses wird etwa 26000 mal aufgerufen)
(Die Schleife selbst ->for(int aa=0;aa<shad_sku.size();aa++)<- ca.65000 mal)Hier das Original mit char-Array:
if (teilupdate==1) { if (strcmp(test[spalmengel],"0")==0) strcpy(app,"x"); strcpy(bigbuffer,""); sprintf(bigbuffer,"%s\t%s\t%s\t%s\t%s\t%s\t%s\t\t\t%s\t%s\t%s\t%s\t%s\t\t\t\t%s\t%s\t%d\t\n",test[spalsku],test[spalautor] ,fattitle,test[spalverlag],test[spaljahr],test[spalformat],test[spalpreis],test[spalmengel],test[spalamazustand],fatnote,test[spalkatamazon],test[spalsprache],amaurl,app,7); for (int aa=0;aa<anzsku;aa++) { if (strcmp(shad[aa].sku,test[spalsku])==0) { if((strcmp(shad[aa].anz,test[spalmengel])!=0)||(strcmp(shad[aa].dat,test[spalaenderung])!=0)) {f << bigbuffer;aa=anzsku;flag=1;NR++;} else {aa=anzsku;flag=1;} } } if (flag==0) {f << bigbuffer;NR++;} rectx=SUMAKT*balkx/SUMMAX;SUMAKT++; }Laufzeit flotte 16 Sekunden.
Dann die Abänderung ins std::string + vector:
bigbuffer ist nun ein stringstream, aber der bremst nicht.if (teilupdate==1) { if (test[spalmengel]=="0") strcpy(app,"x"); bigbuffer << test[spalsku] << "\t" << test[spalautor] << "\t" << fattitle << "\t" << test[spalverlag] << "\t" << test[spaljahr] << "\t" << test[spalformat] << "\t" << test[spalpreis] << "\t\t\t" << test[spalmengel] << "\t" << test[spalamazustand] << "\t" << fatnote << "\t" << test[spalkatamazon] << "\t" << test[spalsprache] << "\t\t\t\t" << amaurl << "\t" << app << "\t" << "7" << "\t\n"; for (int aa=0;aa<shad_sku.size();aa++) { if (shad_sku.at(aa)==test[spalsku]) { if((shad_anz.at(aa)!=test[spalmengel])||(shad_dat.at(aa)!=test[spalaenderung])) { f << bigbuffer.str(); flag=1; NR++; break; } else { flag=1; break; } } } if (flag==0) {f << bigbuffer.str();NR++;} rectx=SUMAKT*balkx/SUMMAX;SUMAKT++; }Laufzeit grobe 60 Sekunden.
Dann nun wieder abgeändert in:
if (teilupdate==1) { if (strcmp(test[spalmengel].c_str(),"0")==0) strcpy(app,"x"); bigbuffer << test[spalsku] << "\t" << test[spalautor] << "\t" << fattitle << "\t" << test[spalverlag] << "\t" << test[spaljahr] << "\t" << test[spalformat] << "\t" << test[spalpreis] << "\t\t\t" << test[spalmengel] << "\t" << test[spalamazustand] << "\t" << fatnote << "\t" << test[spalkatamazon] << "\t" << test[spalsprache] << "\t\t\t\t" << amaurl << "\t" << app << "\t" << "7" << "\t\n"; for (int aa=0;aa<shad_sku.size();aa++) { if (strcmp(shad_sku.at(aa).c_str(),test[spalsku].c_str())==0) { if((strcmp(shad_anz.at(aa).c_str(),test[spalmengel].c_str())!=0)||(strcmp(shad_dat.at(aa).c_str(),test[spalaenderung].c_str())!=0)) { f << bigbuffer.str(); flag=1; NR++; break; } else { flag=1; break; } } } if (flag==0) {f << bigbuffer.str();NR++;} rectx=SUMAKT*balkx/SUMMAX;SUMAKT++; }Also sämtliche string==string und string!=string Vergleiche durch strcmp(x,y)==0/!=0 ersetzt.
Laufzeit grobe 25 Sekunden..at() und .size() Verzicht führt zu keinerlei Veränderung.
Warum ist string==string string!=string langsamer als strcmp() ??
Gibt es da eine Abhilfe?
Gruß,
DC
-
Und welche Compileroptionen? Keine Ahnung was f ist und sonst bleibt auch nur raten uebrig.
.at() und .size() Verzicht führt zu keinerlei Veränderung
Na das wuerde mich stutzig machen.
Warum ist string==string string!=string langsamer als strcmp()?
Hmm, es ist nicht langsamer. Anstatt zu raten, benutze einen Profiler!
-
Hast du meine Ratschläge befolgt (besonders die letzten beiden)?
Ansonsten kann ich mich knivil anschliessen. Und benutze bitte [cpp]- statt [code]-Tags, die haben Syntaxhighlighting.
-
Nexus schrieb:
Hast du meine Ratschläge befolgt (besonders die letzten beiden)?
Ja, habe etliche Kombinationen probiert und es führte zun Nichts.
Vorallokierung mit .reserve() gab auch keinelei Vorteile.Ansonsten kann ich mich knivil anschliessen. Und benutze bitte [cpp]- statt [code]-Tags, die haben Syntaxhighlighting.
[quote]
Okay, habe nun nochmals den Schleifenkörper auf Durchläufe geprüft und muss sagen es sind insgesamt: 2075966830 Durchläufe. !!Jaja, was für ein Wahnsinn!!
(Es werden hier zwei Tabellen miteinander verglichen. Die 1.Tabelle hat knappe 65000 Einträge die 2.Tabelle ca.26000.)Da beide Tabellen aber nach gleichem Kriterium sortiert sind, muß ich garnicht jedesmal die komplette Tabelle nach einem Match durchsuchen, sondern es reicht, wenn ich nach einem Fund, einfach den Schleifenstartindex hochsetze.
(Dadurch verkleinert sich der Suchbereich)
Nachdem ich diese kleine Korrektur vorgenommen hatte, sind es nur noch 64435 Durchläufe.
Auf dieser Basis habe ich nun die strcmp's wieder durch string==string ersetzt und die Zeit ist nun ohne merkliche Unterschiede jedesmal knappe 8 Sekunden.(Hatte auch gestern mal eine Lösung mit <vector>.erase() versucht, aber durch diese dynamische Vectorverkleinerung schrumpfte zwar der Suchbereich, aber es dauerte auch sehr lange, weil das Entfernen eines Vector-Elements wohl auch recht zeitaufwendig ist)
Auf jeden Fall spielt wohl die Anzahl der Schleifen eine Rolle.
Wenn ich nun richtig gerechnet habe ist der Unterschied zwischen strcmp und string==string 0,000000025 Sekunden.
Bei 65000 Durchläufen wären es 0,0016 Sekunden länger.
Und bei 2000000000 Durchläufen schon 50 Sekunden.Gruß,
DC
-
Don Carsto schrieb:
Nexus schrieb:
Hast du meine Ratschläge befolgt (besonders die letzten beiden)?
Ja, habe etliche Kombinationen probiert und es führte zun Nichts.
Vorallokierung mit .reserve() gab auch keinelei Vorteile.Das deckt sich nicht mit deiner anderen Aussage, dass der Verzicht auf at() nichts bringt. Wenn du tatsächlich eine auf Laufzeit optimierte Version von vector benutzt, dann muss dies einen gewaltigen Unterschied machen.
Das klingt so, als wüsstest du deinen Compiler nicht richtig zu bedienen.
-
Okay, mag sein, da fehlt mir auch die Erfahrung. Habe umgestellt von DevC++ mit MinGW 3.xx auf CodeBlocks mit MinGW 4.5.
Da gibt es bei Compileroptionen verschiedene Optimierungsarten für Geschwindigkeit, Größe und Expensive.
Hatte da verschiedene Kombinationen ausprobiert.
Debuggersymbole erzeugen hatte ich auch ausgeschaltet usw.Wie gesagt, meine Compilierugnen mit oder ohne .at() ergab keine signifikanten Geschwindigkeitsvorteile.
Gut, Vielleicht hat CodeBlocks noch nicht alle von MinGW unterstützten Optimierungsarten in seinem Häkchenmenü. Da müßte ich die dann eventuell mal als Zusatzoption einstellen.
Werde mich mal doch näher mit der Anleitung von MinGW beschäftigen.
-
Dass .at() vs. [] keinen (messbaren) Unterschied macht wundert mich nicht.
Mich wundert eher, dass bei strcmp() vs. string == string die strcmp() Variante schneller sein soll.
Wenn überhaupt ein Unterschied ist, dann müsste string == string schneller sein, da es z.B. bei unterschiedlicher Länge sofort "false" melden kann, wohingegen strcmp noch entscheiden muss ob "1" oder "-1" (also welcher String "vor" dem anderen kommt).
Hast du diesen Unterschied, also strcmp vs. operator ==, auch in einem "Release Build" (=volle Optimierungen) getestet? Oder war das vielleicht mit einem "Debug Build"?
Bei einem Debug-Build kann ich mir das nämlich leicht vorstellen, da strcmp() meist gut optimierter C-Code ist, der auch ohne Optimierungen einigermassen schnell läuft ... wohingegen operator == für Strings oft nicht so gut optimiert ist. Bzw. es können da Dinge wie Debug-Iteratoren reinpfuschen.
-
std::vector<std::string> sprache({"deu", "eng"});sollte btw auch funktionieren.
-
Ja, habe sämtliche Optimierungen aktiviert, Debugmodus deaktiviert.
Aber wie schon gesagt, der Unterschied zwischen strcmp() und str==str betrug nur 0,000000025 Sekunden pro Schleifendurchlauf.
Was sich dann bei 2075966830 Schleifendurchläufen als 50 Sekunden manifestierte.
Jetzt, wo es nur noch knappe 64000 Durchläufe sind, hat es sich relativiert.Dann habe ich heute auch mal den Code auf Iteratoren umgestellt, aber das ergab auch nicht die dollen sichtbaren Unterschiede. Ob nun 8,5 oder 8,2 oder 8,8 Sekunden ist eingentlich egal, es ging eher um den Unterschied von 16 Sekunden zu 60 Sekunden.
Mal sehen, vielleicht entdecke ich ja bei weiteren Forschungen doch noch einen Beschleuniger. Vielleicht einen anderen Containertyp ausprobieren usw.Gruß,
DC
-
Don Carsto schrieb:
Aber wie schon gesagt, der Unterschied zwischen strcmp() und str==str betrug nur 0,000000025 Sekunden pro Schleifendurchlauf.
Was sich dann bei 2075966830 Schleifendurchläufen als 50 Sekunden manifestierte.(...)
ging eher um den Unterschied von 16 Sekunden zu 60 Sekunden.
Ich würde 44 von 60 Sekunden schon viel nennen.
Wenn du andrer Meinung bist, dann überweis' mir einfach monatlich 73% deines Gehalts
-
Hmm, offensichtlich falsch verstanden also erörtere ich nochmal:
Ohne STL string benötigte das Schleifenmonster 16 Sekunden.
Mit STL string dann 60 Sekunden.
Was ich auch als zu viel ansah. (Also nix mit 73% meines Gehalts
)
Da aber alle Massnahmen, ohne STL string wieder zu entfernen nicht wirklich griffen, habe ich mal die Schleife analysiert und kam zu der Erkenntnis, dass über 2 Milliarden Durchläufe nicht wirklich effizient sind.
Also veränderte ich die Schleife so, daß sie sich nun nach jedem Match dynamisch verkleinert.
Das führte dann dazu, daß sie nur noch knappe 8 Sekunden benötigte.Das ist entgegen der 60 Sekunden ein enormer Zeitvorteil von kanpp 50 Sekunden.
Hier nun noch Iteratoren einbauen oder weglassen, oder mit/ohne .at() arbeiten führte zu kaum sichtbaren Veränderungen, weil die Durchlaufphasen eh zwischen 8,1 und 8,6 Sekunden schwankten.
Mit diesen knappen 8 Sekunden kann ich gut schlafen, weil ja der Ursprungscode ohne STL strings mit Monsterschleife bereits 16 Sekunden benötigte.
Ich habe nun die Sicherheit von STL string und vector und durch die zulässige Schleifenverkürzung satte 8 Sekunden Ersparnis.
Würde ich nun wieder die verkürzte Schleife wieder auf "ohne STL string" umbasteln, dann hätte ich keinerlei Zeitersparnis, weil ja in meinem Fall hier ein Schleifendurchlauf mit STL string 0,000000025 Sekunden länger benötigt als ohne STL string.
Was dann nun bei nur noch 65000 Durchläufen insgesmat 0,002 Sekunden ausmacht.Erst ab 65 Millionen Durchläufen kann man es dann als 1 Sekunde bemerken.
Und bei 2 Milliarden sind es bereits 50 Sekunden.Zusammenfassend kann ich nun folgendes schreiben:
Vorher: Code unsicher, unleserlich, schnell. 16 Sekunden
Eventuelle unvorhersehbare mögliche Ausnahmefehler.Während der Umstellung, bösen Fehler durch zu kurz gewähltes Array entdeckt.
Monsterschleife entlarvt die Ineffizienz erzeugte.Nachher: Code sehr sicher, leserlicher, schnell. 8 Sekunden
Allein die Handhabung mit vector.push_back und vector.size() bietet soviel Vorteile, daß ich total begeistert bin.Also, ich freu mich.. :p
PS: Habe zwar immer noch nicht herausgefunden ob und wie der MinGW noch spezielle Optimierungen für diesen Fall einstellbar hat, aber ich freu mich trotzdem...

Gruß,
DC
-
Und wo genau hast du jetzt bewiesen, dass strcmp schneller ist? Deine 0,0..025 s koennen auch ganz andere Ursachen haben. Also stell nicht irgendwelche Behauptungen auf, um die es dir in Wirklichkeit gar nicht geht.
-
Naja,wenn ich beide Male den identischen Code zum Einen mit strcmp nutze und zum Anderen mit std::string und es gibt einen Zeitunterschied, dann ist in meinem Fall nunmal das strcmp schneller.
Teile ich nun die Mehrzeit durch die Gesamtzahl der Schleifendurchläufe so komme ich auf den Zeitunterschied pro Schleifendurchlauf.
0,0....25 Sekunden.Ich will ja nicht beweisen, dass strcmp IMMER schneller ist, aber in diesem Fall ist es bei MIR nunmal schneller.
Warum auch immer. Villeicht liegt es doch am Compiler, aber dazu habe ich in den Tiefen des Netzes nichts gefunden.Aber bei nur noch 65000 Schleifendurchläufen ist es halt nicht mehr messbar schneller.
-
@Don Carsto:
Ich hab dich schon richtig verstanden, ich hab mich nur bei den Zahlen vertan (16 statt 25).Vor der Optimierung des Algorithmus hattest du die Version die 2 Mrd. Duchläufe macht.
Diese hattest du 1x mit std::vector/std::string und operator == und einmal mit std::vector/std::string und strcmp() gemessen.
Mit operator == hattest du 60 Sekunden und mit strcmp() 25 Sekunden.
Und das ist ein massiver Unterschied.
(Ich beziehe mich auf diesen Beitrag hier: http://www.c-plusplus.net/forum/p2000196#2000196)Wieviel das in absoluter Zeit pro String-Vergleich ist, ist mir relativ egal. Interessant ist bloss, dass alleine durch die Umstellung von operator == zu strcmp() fast 60% der Laufzeit eingespart werden konnten. Und bei einer Laufzeit im Sekunden-Bereich finde ich das nicht mehr wenig.
Nach der Umstellung des Algorithmus braucht dein Code mit operator == jetzt "nur" mehr 8 Sekunden. Ausgehend vom Vergleich mit 2 Mrd. Durchläufen müsste er aber mit strcmp() in unter 4 Sekunden laufen. Immer noch etwas was ich als deutliche Verbesserung ansehen würde.
Und interessant finde ich es deswegen, weil es mMn. nicht so sein dürfte.
Es gibt viele Bereiche wo typische STL Implementierungen langsamer sind als die alten C-Funktionen (iostreams vs. FILE* z.B.), aber operator == von std::string gehört eben nicht dazu. Von daher ... komisch.