Performance-Problem in der Konsole
-
Hallo!
Ich bin gerade dabei ein kleines Spielchen als Übung zum C++ lernen zu schreiben. Ein Teil des Spiels soll so funktionieren, dass auf der Konsole irgendwas schnell hin- und herläuft, und man eine Taste drücken muss, wenn es in der Mitte liegt, um zu treffen. Damit das dann nicht in 1 Sekunde 100mal durchläuft, hab ich die eine Wartefunktion benutzt, allerdings hab ich den Ablauf danach mal analysiert und ausgerechnet, dass das Programm durchschnittlish für jede Ausgabe 20ms benötigt und danach noch 10ms wartet. Das ist dann natürlich viel zu langsam und macht das Spiel zu einfach. Ich dachte erst, dass das an meinem uralten Rechner liegt (Win98, 400Mhz) und hab das ganze einem Kumpel geschickt, der ne 3Ghz-Maschine hat. Allerdings lief das Programm dort LANGSAMER (!!!) als bei mir, trotz eingestellter Echtzeit-Priorität. Kann mir bitte jemand erklären woran das liegt und ne Möglichkeit sagen, wie ich die Performance verbessern kann?
Hier mein Code:
#include<conio.h> #include<iostream> #include<cstdlib> void delay(DWORD Delay) { DWORD dwTicks = GetTickCount(); while (GetTickCount()-dwTicks < Delay); } void cls() { COORD coordScreen = { 0, 0 }; /* here's where we'll home the cursor */ BOOL bSuccess; DWORD cCharsWritten; CONSOLE_SCREEN_BUFFER_INFO csbi; /* to get buffer info */ DWORD dwConSize; /* number of character cells in the current buffer */ HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); /* get the number of character cells in the current buffer */ bSuccess = GetConsoleScreenBufferInfo(hConsole, &csbi); dwConSize = csbi.dwSize.X * csbi.dwSize.Y; /* fill the entire screen with blanks */ bSuccess = FillConsoleOutputCharacter(hConsole, (TCHAR) ' ', dwConSize, coordScreen, &cCharsWritten); /* get the current text attribute */ bSuccess = GetConsoleScreenBufferInfo(hConsole, &csbi); /* now set the buffer's attributes accordingly */ bSuccess = FillConsoleOutputAttribute(hConsole, csbi.wAttributes, dwConSize, coordScreen, &cCharsWritten); /* put the cursor at (0, 0) */ bSuccess = SetConsoleCursorPosition(hConsole, coordScreen); return; } int main() { DWORD anfang = GetTickCount(); do { for(int i=0;i<78;i++) { for(int j=0;j<i;j++) { std::cout<<" "; } std::cout<<"###"; delay(10); cls(); } for(int i=78;i>0;i--) { for(int j=0;j<i;j++) { std::cout<<" "; } std::cout<<"###"; delay(10); cls(); } }while(!kbhit()); }
Ich hab mir schon überlgt, dass es vllt günstiger wäre, statt dauernd Leerzeichen zu schreiben, einfach den Cursor immer um eine Position weiterzusetzen, aber das irgendwie nicht hinbekommen.
Danke schonmal, phyll
-
Jap, du schreibst viel zu viel zu viel und benutzt zudem noch eine Delay-Funktion die unbrauchbar ist
Includiere die <windows.h> und verwende statt deinem Delay() die Funktion Sleep(millis).
Zur Ausgabe: Wie du auch cls() implementiert hast, erstellst du dir ein gotoxy() mit WinAPI-Konsolenfunktionen (SetConsoleCursorPosition). Danach setzt du es an die alte Stelle, überzecihnest sie mit einem Leerzeichen und dann an die neue Stelle und zeichnest das Zeichen. Außerdem ist die Ausgabe über cout langsam und gepuffert, überlege hier stattdessen WriteConsole() einzusetzen.
Wenn du cls() nur irgendwoher kopiert hast und von den WinAPI-Konsolenfunktionen keine Ahnung hast empfehle ich: http://ic.c-plusplus.net
MfG SideWinder
-
Danke, Problem ist gelöst. Das ganze läuft jetzt 12 mal so schnell. Woran liegt es eigentlich, dass Ausgaben immer so fürchterlich langsam passieren? (Ich hab mal einen Primzahlfinder geschrieben, bei dem die Ausgabe der gefundenen Zahlen 4/5 der Rechenzeit brauchte...)
-
Das liegt in der Natur der Konsole, die Ausgabe ist da nicht besonders schnell. Zudem macht cout noch einen furchtbaren Aufstand mit den Daten.
MfG SideWinder
-
Servus, ich hole hier mal meinen alten Thread raus um keinen neuen aufzumachen...Im Kern geht es um was ähnliches wie letztes Mal: Ich hab einen kleinen Reaktionstester programmiert, hier der Code:
#include <iostream> #include <windows.h> #include <conio.h> using namespace std; int main() { srand((unsigned)time(NULL)); cout<<"Dieses Programm testet deine Reaktionszeit. Druecke, sobald etwas auf\n" <<"dem Bildschrim erscheint, so schnell du kannst eine Taste. Danach\n" <<"wird dir angezeigt, wie lang du gebraucht hast. ESCAPE beendet das\n" <<"Programm. Mit einer anderen Taste beginnt der Test."<<endl; getchar(); while(!(kbhit() && getch() == 27)) { Sleep(rand() % 5000 + 1000); cout<<"###################### Taste druecken! #########################" <<endl; DWORD end; DWORD start = GetTickCount(); while (1) { if (kbhit() && getch() != 27) { end = GetTickCount(); break; } if (kbhit() && getch() == 27) { exit(0); } } cout<<"Deine Reaktionszeit war: "<<end-start<<" Millisekunden."<<endl; } }
Das funzt soweit auch ganz gut, nur scheint mir, dass die Reaktionszeiten sehr lang sind, die das Ding ausgibt. Das letzte Mal, als ich so nen Test gemacht hab, hatte ich immer unter 200ms, aber hier schaffe ich kaum noch 250.
Aber wo liegt die "Bremse"? Außerdem kommt es manchmal vor, dass man zweimal drücken muss, bevor die Zeit angezeigt wird. Und wenn man zu früh eine Taste drückt, dass zeigt es einen Reaktionszeit von 0 an. Ich habe versucht das mit
cin.ignore(cin.rdbuf()->in_avail()); zu beheben, aber kbhit() benutzt offenbar nicht den gleichen Buffer wie cin.