Untersuchung der optimalen Schlaf-Zeit-Berechnung im Spiel-Schleife

Wenn die Programmierung von Animationen und kleine Spiele, die ich bin gekommen, um zu wissen, die unglaubliche Bedeutung der Thread.sleep(n); verlasse ich mich auf diese Methode, um das Betriebssystem anweisen, wenn meine Anwendung nicht benötigen, CPU, und mit diesem macht mein Programm die Fortschritte, die in vorhersehbarer Geschwindigkeit.

Mein problem ist, dass die JRE verwendet verschiedene Methoden der Implementierung dieser Funktionalität auf verschiedenen Betriebssystemen. Auf UNIX-basierten (oder beeinflusst) OS:es-wie Ubuntu und OS X, die zugrunde liegenden JRE Implementierung verwendet werden, eine gut funktionierende und präzises system für die Verteilung von CPU-Zeit für verschiedene Anwendungen, und so macht mir mein 2D-Spiel glatt und lag-frei. Jedoch auf Windows 7 und ältere Microsoft-Systemen, die CPU-Zeit-Verteilung scheint zu funktionieren unterschiedlich, und Sie erhalten in der Regel wieder Ihre CPU-Zeit, die nach der gegebenen Menge an Schlaf, variierend mit etwa 1-2 ms vom Ziel schlafen. Jedoch bekommen Sie gelegentliche Ausbrüche von extra 10-20 ms der Zeit schlafen. Dies bewirkt, dass mein Spiel lag einmal alle paar Sekunden, wenn dies geschieht. Ich habe bemerkt, dass dieses problem existiert auf den meisten Java-Spiele, die ich habe versucht, auf Windows, Minecraft wird ein spürbares Beispiel.

Nun, ich habe auf der Suche im Internet um eine Lösung zu finden für dieses problem. Ich habe gesehen, eine Menge Leute mit nur Thread.yield(); statt Thread.sleep(n);, die funktioniert einwandfrei auf Kosten der aktuell verwendeten CPU-Kern immer Volllast, egal, wie viel CPU-Ihr Spiel auch tatsächlich braucht. Dies ist nicht ideal für das Spiel auf laptops oder high-Energie-Verbrauch-workstations, und es ist ein unnötiger trade-off auf Macs und Linux-Systeme.

Suchen, um weiter fand ich eine weit verbreitete Methode der Korrektur Zeit schlafen Inkonsistenzen namens "spin-Schlaf", wobei Sie nur um den Schlaf, für 1 ms zu einer Zeit und überprüfen Sie für die Konsistenz mit der System.nanoTime(); Methode, die sehr genau ist, auch auf Microsoft-Systemen. Dies hilft, die für den normalen 1-2 ms der Schlaf Ungereimtheit, aber es wird nicht helfen gegen die gelegentlichen Ausbrüche von +10-20 ms Schlaf Inkonsistenz, da dies oft dazu führt, dass mehr Zeit verbracht, als einen Zyklus von meiner Schleife sollten alle zusammen.

Nach Tonnen zu suchen, fand ich diese kryptischen Artikel von Andy Malakov, die war sehr hilfreich bei der Verbesserung meiner Schleife: http://andy-malakov.blogspot.com/2010/06/alternative-to-threadsleep.html

Basiert auf seinem Artikel schrieb ich diese sleep-Methode:

//Variables for calculating optimal sleep time. In nanoseconds (1s = 10^-9ms).
private long timeBefore = 0L;
private long timeSleepEnd, timeLeft;

//The estimated game update rate.
private double timeUpdateRate;

//The time one game loop cycle should take in order to reach the max FPS.
private long timeLoop;

private void sleep() throws InterruptedException {

    //Skip first game loop cycle.
    if (timeBefore != 0L) {

        //Calculate optimal game loop sleep time.
        timeLeft = timeLoop - (System.nanoTime() - timeBefore);

        //If all necessary calculations took LESS time than given by the sleepTimeBuffer. Max update rate was reached.
        if (timeLeft > 0 && isUpdateRateLimited) {

            //Determine when to stop sleeping.
            timeSleepEnd = System.nanoTime() + timeLeft;

            //Sleep, yield or keep the thread busy until there is not time left to sleep.
            do {
                if (timeLeft > SLEEP_PRECISION) {
                    Thread.sleep(1); //Sleep for approximately 1 millisecond.
                }
                else if (timeLeft > SPIN_YIELD_PRECISION) {
                    Thread.yield(); //Yield the thread.
                }
                if (Thread.interrupted()) {
                    throw new InterruptedException();
            }
                timeLeft = timeSleepEnd - System.nanoTime();
            }
            while (timeLeft > 0);
        }
        //Save the calculated update rate.
        timeUpdateRate =  1000000000D / (double) (System.nanoTime() - timeBefore);
    }
    //Starting point for time measurement.
    timeBefore = System.nanoTime();
}

SLEEP_PRECISION Ich setzen in der Regel etwa 2 ms, und die SPIN_YIELD_PRECISION etwa 10 000 ns für beste performance auf meinem Windows 7-Maschine.

Nach Tonnen von harter Arbeit, das ist der absolute beste, die ich mit oben kommen kann. So, da ich noch Sorge um die Verbesserung der Genauigkeit von diesem Schlaf-Methode, und ich bin immer noch nicht zufrieden mit der performance, ich möchte den Appell an Sie alle, die Sie java game Hacker und Animatoren gibt Vorschläge für eine bessere Lösung für die Windows-Plattform. Könnte ich ein Plattform-spezifische Art und Weise auf Windows, es besser zu machen? Ich kümmern sich nicht darum, eine kleine Plattform-spezifischen code für meine Anwendungen, solange der Großteil des Codes ist OS unabhängig.

Ich würde auch gerne wissen, ob es jemanden gibt, der weiß, über Microsoft und Oracle arbeiten, eine bessere Umsetzung der Thread.sleep(n); Methode, oder was die Oracle-Pläne für die Zukunft auf die Verbesserung Ihrer Umwelt als Grundlage der Anwendungen, die hohe timing-Genauigkeit, wie Musik, software und Spiele?

Danke Euch allen für das Lesen meiner langen Frage/Artikel. Ich hoffe einige Leute finden meine Forschung hilfreich!

  • Hvae Sie versucht, indem Sie geplante tasks, um eine ScheduleExecutorService. Diese erlauben es, bestimmte Aufgabe je 1 ms oder ziemlich nah dran.
  • Sind Sie sicher, dass die 10-20 ms of sleep time ist, was die Ursache der Verzögerung? Selbst bei 50FPS, das ist nur ein einziges Bild, das verworfen wird, oder solange verzögert, bis sein Nachfolger. Vielleicht ist es die Formel, die Sie berechnen die Positionen Ihrer sprites statt.
  • Lawrey - tatsächlich, in einigen Situationen ScheduledExecutorService ausführen kann schlimmer geworden, seit es nutzt die nano-mal-api. wir haben Situationen erlebt, in denen die nano-mal Zeug war völlig unzuverlässig unter windows (vor allem, wenn die Ausführung als virtuelle Gäste).
  • Nein, ich bin nicht wirklich tot sicher. Ich habe mein bestes versucht, mit verschiedenen benchmarks und versuchen pin nach dem problem, aber ich habe nicht in der Lage, um herauszufinden, eine ganze Menge. Nach Barfieldmv die Antwort, das lag vielleicht tatsächlich schlimmer, als ich dachte. Derzeit bin ich eigentlich nur zeichnen von gefüllten Rechtecken, also ich glaube nicht, dass ich irgendein problem mit meinem sprite-Algorithmus, da es keines gibt.
InformationsquelleAutor Emanuel | 2011-03-11
Schreibe einen Kommentar