Mit Auslagerung in einen Arbeitsthread wird mein Programm lahm - wieso?
-
Hallo!
Mit Threads geht alles schneller, weil man zeitraubende Aufgaben auslagern kann.
So habe ich das verstanden und wollte es nutzen.Ich hatte bisher:
Eine Klasse, die NUR statische Variablen und Funktionen hat, damit man sie bequem aufrufen kann.
Diese Klasse bekomt einen String und schreibt den je nach Wunsch in eine Datei und / oder Traced ihn.
Das war langsam, aber kaum spürbar auf dem Entwicklungspc. Nun ist der Zielpc aber eher deutlich langsamer und deswegen sollte das Rausschreiben im Thread passieren.Also habe ich folgendes gemacht:
void CLog::LogLine(UINT f_nLogNummer, CString f_strText) { // Parameter merken CLog::s_nLogNummer = f_nLogNummer; CLog::s_strText = f_strText; // Thread anwerfen AfxBeginThread(CLog::LogLineIntern, 0, 0, 0, 0, NULL); // Parameter sicherheitshalber nullen CLog::s_nLogNummer = 0; CLog::s_strText = _T(""); }
Und in LogLineIntern wird der ganze Kram gemacht.
UINT CLog::LogLineIntern(LPVOID pParam) { // Hier wurde NICHTS geändert - sollte also okay sein. AfxEndThread(0, TRUE); // Thread beenden return 0; }
Bisher brauchte das Programm zum Starten 5 bis 10 Sekunden, dann kam das Anmeldefenster.
Jetzt kommt das nach 3 MINUTEN.Ich glaube, meine Idee war Mist.
Was läuft da schief?
Achja, diese Funktion wird DAUERND aufgerufen, weil so ziemlich in jeder Funktion mindestens ein Aufruf davon steht.
-
ein Sleep(0) in einem Thread wirk wunder.
-
Leider nein.
Es ist immer noch schnarchlahm.
UINT CLog::LogLineIntern(LPVOID pParam) { Sleep(0); // Hier wurde NICHTS geändert - sollte also okay sein. AfxEndThread(0, TRUE); // Thread beenden return 0; }
-
// Hier wurde NICHTS geändert - sollte also okay sein.
Was soll das bedeuten?
Sieht die Funktion jetzt wirklich so in deinem Code aus:
UINT CLog::LogLineIntern(LPVOID pParam) { Sleep(0); // Hier wurde NICHTS geändert - sollte also okay sein. AfxEndThread(0, TRUE); // Thread beenden return 0; }
-
Nein, so sieht die nicht aus. Aber der Teil ist unverändert seit über einem Jahr - daher sehe ich ihn als fehlerfrei an.
Aber auch wenn ich den Rest in der Funktion auskommentiere bleibt es lahm. Keine spürbare Verbesserung und erst recht nicht so schnell wie gewohnt.
Ich habe das Gefühl, dass dieses "Thread her" "Thread weg" das verlangsamt.
Zur Veranschaulichung, was ich unter "lahm" verstehe, habe ich mal den Programmstart bis zur Anmeldemaske gefilmt:
Ohne Thread http://www.larsaf-iii.de/forum/schnell.mp4
Mit Thread http://www.larsaf-iii.de/forum/lahm.mp4
Allerdings braucht mal Quicktime, um die Filme zu sehen. Sorry auch für das Flimmern, weder die Neonröhre noch die Monitore sind Digicam-freundlich und das ist nur mit dem Handy gefilmt.Das wichtigste ist aber zu erkennen: Auf dem linken Monitor kommt die Autorenversionsmeldung und auch die Anmeldemaske.
Auf dem rechten Monitor laufen die Traces (Debugausgabe VC).
Und die Zeitanzeige spricht ihre eigene Sprache.PS: Wer Scooter nicht mag, sollte den Ton ausschalten.
-
die filme sind irgendwie kaputt
flimmern nur pixel blöcke rum.
-
Bei mir gehts aber...
Es sei denn, du meinst, dass die generell flimmern, dazu hatte ich aber was geschrieben.
-
Du solltest auch nicht Sleep(0) am Anfang des Thread machen.
Dort macht es keien Sinn. Sleep(0) gibt das Zeitfenster für die Ausführung wieder an Windows zurück und Windows Entscheidet dann wer es bekommt. Ist Zeit dann wieder dein Thread sonst mal eine andere komponente. Ohne Sleep kann man feststellen das dein Programm 99% der Resourcen verbraucht weil ja kein anderes Programm arbeitet.
Das macht dein Thread. Mit Sleep(0) kannst du das abstellen und gibt eben das Zeitfenster einem anderen Thread. Also in deinem Schleifencode des Thread öfter Sleep(0) aufrufen.z.B. Wenn du jede Datei eines DIR öffnest dann eben vor jedem öffnen der Datei.
Dies musst du eben austesten bis es besser wird.
-
Hmm, ich glaube, dann hilft es nix mit dem Thread, denn eigentlich macht der nicht viel:
UINT CLog::LogLineIntern(LPVOID pParam) { Sleep(0); // Soll überhaupt etwas protokolliert werden? Und passt die Nummer? if ((CLog::s_fDatei || CLog::s_fTrace) && (s_Zahlenbereiche.Includes(s_nLogNummer))) { // Hier wird die spätere Ausgabe zusammengebaut CString strZeile; // Aktuelle Zeit und Datum holen COleDateTime tmNow = COleDateTime::GetCurrentTime(); // Die Ausgabezeile bekommt folgendes Format: // Kennnummer (Benutzerkürzel: Zeit+Datum) Freitext // Beispiel: // 123456 (BLA: 10:00:00 01.04.00) Es wurde was gemacht. strZeile.Format(_T("%5d: (%s: %s) %s\n"), s_nLogNummer, CLog::s_strBenutzer, tmNow.Format(_T("%d.%m.%y %H:%M:%S")), s_strText); // Soll überhaupt eine Ausgabe in die Datei gemacht werden? if (CLog::s_fDatei) { CStdioFile datei; CString strDateiname; strDateiname.Format(_T("%s\\%s.log"), CLog::s_strLogPfad, tmNow.Format(_T("%Y_%m_%d"))); if (datei.Open(strDateiname, CFile::modeWrite|CFile::modeCreate|CFile::modeNoTruncate)) { // Ans Ende der Datei springen datei.SeekToEnd(); // Die Zeile reinschreiben datei.WriteString(strZeile); // Die Datei schliessen datei.Close(); } #ifdef _DEBUG // Nur im Debugmodus einen Fehler melden. Der Benutzer hat mit dem Loggen nichts zu tun. else { // Es trat ein Fehler auf - Meldung nur im Debugmodus TRACE("!!!!!!!!!!!!!!!! Die Datei (" + CString( GetCommandLine()).Mid( 1, CString(GetCommandLine()).ReverseFind('\\')-1) + _T("\\") + strDateiname + ")konnte nicht geöffnet werden! !!!!!!!!!!!!!!!!!!!\n"); ASSERT(FALSE); } #endif } #ifdef _DEBUG // Das TRACE gibt es im Releasemodus nicht, also kann man die if auch weglassen. // Soll eine Debugausgabe gemacht werden? if (CLog::s_fTrace) { TRACE(_T(" %s"), strZeile); } #endif } AfxEndThread(0, TRUE); return 0; }
So, das war jetzt mal die Funktion ungekürzt.
Eigentlich wenig, aber weil sie so oft aufgerufen wird, dachte ich, es wäre besser, sie auszulagern.
-
So, ich gebe an dieser Stelle auf und gehe zu einer Alternativlösung über:
http://www.c-plusplus.net/forum/viewtopic.php?t=100900Trotzdem interessiert mich noch, warum das so langsam war und was ich falsch gemacht hatte.
Da es wohl ein grundlegendes Problem ist, werde ich früher oder später wieder davor stehen.
-
Mach doch mal eine Zähl-Variable rein und guck wie oft du die Funktion aufrufst bis die Anwendung gestartet ist.
-
Das brauche ich nicht nachzählen, das ist SEHR OFT.
Deswegen suche ich doch nach Wegen, um Zeit zu sparen...
-
gut das du so genaue angaben machst.
ich würde mal im taskmanager nachgucken wieviele threads da gleichzeitig ablaufen.
kannst du es nicht so machen das du nur einen thread machst der die sachen loggt anstatt für jede kleine ausgabe einen thread zu starten?
-
Das habe ich schon gemacht:
7 bis 9 sind es.Meistens schwankt es zwischen 8 und 9.