Jump to content

  • Log In with Google      Sign In   
  • Create Account


Timer vs. thread.sleep();


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
13 replies to this topic

#1 EpicWally   Members   -  Reputation: 282

Like
0Likes
Like

Posted 11 September 2012 - 09:51 AM

I am new to Java (and OOP in general) and have recently been trying my hand at programming some basic games. My first two attempts used a Timer, with an ActionListener to call for game updates, which seemed to work pretty smoothly (granted these games only used a text interface.) In preparing for my most recent game (a breakout clone) I noticed another user on the forum using a sleep() inside a game thread. My initial observations of this in both his game, and in my own when I implemented it, was that the speed didn't feel constant, like the game would randomly speed up and slow down, presumably on processor load. Is this just a problem with implementation? Which is the preferred method, Timers, or threads? If it is threads, which my gut feel seems to be, how would you avoid this problem? Should the game thread that updates movement etc be a separate thread than the one that calls for screen refreshes?

Thank you for the guidance.

Sponsor:

#2 SimonForsman   Crossbones+   -  Reputation: 5718

Like
1Likes
Like

Posted 11 September 2012 - 10:07 AM

Sleep should only be used as a way to preserve the battery on mobile devices (Which tend to behave far better when sleeping aswell), you could include a laptop mode that sleeps for a short period of time after each update if your game is playable that way (don't rely on it to control the speed at which the application runs though), For a desktop game you should preferably grab the system time in your main loop. (updating via actionlisteners and Timer objects is quite a wierd way to go about things but that works aswell)

Keep things in a single thread until you absolutely have to use more.


System.nanoTime() should give you the most accurate timer for your platform.

Edited by SimonForsman, 11 September 2012 - 10:11 AM.

I don't suffer from insanity, I'm enjoying every minute of it.
The voices in my head may not be real, but they have some good ideas!

#3 samoth   Crossbones+   -  Reputation: 4465

Like
1Likes
Like

Posted 11 September 2012 - 11:28 AM

Sleep should only be used as a way to preserve the battery on mobile devices (Which tend to behave far better when sleeping aswell)

Could you explain why? Although I admittedly don't know how Java implements timers, doing so in any other way than using the timer functionality built into the operating system would be quite dumb, to be honest.

Blocking on a timer and blocking on sleep should be exactly the same in respect of CPU cycles and power consumption. Except that on at least one major operating system (Windows), blocking on a timer has a much better precision and reliability than sleeping. Sleeping will give away the remainder of the time slice and not schedule the thread again before some time, rounded up to the next 16 or so milliseconds. Blocking on a timer puts the thread on the ready list the moment the timer expires and dynamically boosts the thread priority, scheduling it before other and possibly interrupting running threads with the same (original) priority. That's a difference between "yeah, some time, eventually" and "as soon as we can handle it".

#4 EpicWally   Members   -  Reputation: 282

Like
0Likes
Like

Posted 11 September 2012 - 11:29 AM

Hmm, thank you for the tips. So your reccomendation would be to do something to the effect of:

while(playing){
currentTime = System.currentTimeMillis();
if(currentTime > lastTime + updateFrequency){
lastTime = currentTime;
update();
render();
//other game code here
}
}

Did I understand your suggestion correctly? This still looks like it has a potential (albeit small one) for the update frequency to not always be perfect (granted, each cycle where the if statement is false should not take long, so I would doubt you would overshoot your preferred update frequency by more than a ms or two.)

Another thought I had, between posting this and now, would be along a similar line, but still using sleep would do something like:

while(playing){
update();
render();
long currentTime = System.currentTimeMillis();
long sleep = updateFrequency - (currentTime - lastTime);
try{
Thread.sleep(sleep);
}catch(Exception e){}
long lastTime = System.currentTimeMillis();
}

This would allow your delay between cycles to scale based on how long each cycle took, preserving a constant time between cycles (as long as your cycles weren't taking more time than your updateFrequency, which could bugger things up.) I know you said sleep is not the best option, but do you think this would work? My gut feel is that this is cleaner, as your thread is only running when it needs to (once every update cycle) instead of running constantly, continuously checking the system time when it doesn't need to. Not that it's a big overhead. Again, pretty new to this. Just trying to get a good understanding of the pros and cons to all of the possible approaches.

Thanks again for your advice.
-Wally


Edit: I just tried the second idea I mentioned above, and it had the desired effect. I don't know if in a bigger game this would still work as well, or if it only seems to work because of the simplicity of the game.

Edited by EpicWally, 11 September 2012 - 11:56 AM.


#5 !Null   Members   -  Reputation: 380

Like
2Likes
Like

Posted 11 September 2012 - 12:32 PM

Sleep should only be used as a way to preserve the battery on mobile devices (Which tend to behave far better when sleeping aswell).


This is not totally true. I will give you a quote from the book 'killer game programming in java'

"sleep() causes the animation thread to stop executing, which frees up the CPU for other taks, such as garbage collection by the JVM. without a period of sleep, the GamePanel thread could hog all the CPU time"

I mainly sleep to keep a constant FPS, there are many ways to do this, but the amount of time Thread.sleep() should sleep for, should not be a constant number, that's probably why you had that laggy feeling effect.


This book is a good one and I would recommend it.
/********************************************************************************\
/**********************He Who Dares, Wins**********************************\
/********************************************************************************\

#6 slicer4ever   Crossbones+   -  Reputation: 3074

Like
0Likes
Like

Posted 11 September 2012 - 01:24 PM

this is more of a Time-Step problem, http://gafferongames.com/game-physics/fix-your-timestep/

In short, your attempting to run your game at a fixed rate, as such, you need some mechanism to ensure that the frequency continues at a consistant rate(and that your targeted hardware is capable of performing at that rate).

Thread sleep is not reliable the way timers are, most modern hardware can switch back to your thread in ~15ms, but by no means is that set in stone, nor should you rely on that to exist. you can use sleep if you use a proper time-step code, but do remember that sleep is more-so for saving battery power, then to be used as a reliable timer system.
Check out https://www.facebook.com/LiquidGames for some great games made by me on the Playstation Mobile market.

#7 Froyo   Members   -  Reputation: 201

Like
0Likes
Like

Posted 11 September 2012 - 08:13 PM

I've had pretty good results with Thread.sleep() but I haven't tried using a timer so I can't speak about that.

I had a 2D game with a top-down view (like Zelda LttP or Pokemon) and I've ran it for 45 minutes to an hour with 0 frames lost at 30 frames (and game.updates()) per second. Haven't tried it any higher but that's only because I don't have a reason to.

#8 SimonForsman   Crossbones+   -  Reputation: 5718

Like
1Likes
Like

Posted 11 September 2012 - 11:04 PM

Could you explain why? Although I admittedly don't know how Java implements timers, doing so in any other way than using the timer functionality built into the operating system would be quite dumb, to be honest.

Blocking on a timer and blocking on sleep should be exactly the same in respect of CPU cycles and power consumption. Except that on at least one major operating system (Windows), blocking on a timer has a much better precision and reliability than sleeping. Sleeping will give away the remainder of the time slice and not schedule the thread again before some time, rounded up to the next 16 or so milliseconds. Blocking on a timer puts the thread on the ready list the moment the timer expires and dynamically boosts the thread priority, scheduling it before other and possibly interrupting running threads with the same (original) priority. That's a difference between "yeah, some time, eventually" and "as soon as we can handle it".


Sleep just wraps the OS sleep function, which means your 1ms sleep could end up taking 10+ ms on Windows (it works for some games but for 60fps it will reduce the players experience, which is why i only recommend it as an option, on Android OTOH sleep can be used to control runspeed(in foreground activities) without much problems (It seems to wake up the exact millisecond you asked for each time)).

Timers (as in the Timer class) in Java work reasonably well (on some platforms, i havn't actually tried them on Windows in a very long time), their problem is that they spawn a new thread, they don't touch the currently running thread. There are two classes named Timer in Java (big wtf imo), one in Swing which uses ActionListeners (These are the ones the OP are using) , these create a new thread per timer object and the execution frequency is set per Timer, They have some synchronization overhead since the actual execution is done in the gui thread, not the Timer objects thread). (The actionListener is called by the swing event loop when it encounters the event sent by the Timer object, so even if the event is sent on time it will never be executed on time(Allthough the eventloop runs fast enough i guess)). (Swing imo is a piece of shit API, GUI apps in Java are better off using for example wxWidgets or QT, Games benefit more by using for example LWJGL or Slick.

The second Timer class is in util and uses TimerTasks , these also create a background thread per Timer but can have multiple scheduled tasks(With different frequencies or delays) per Timer, these tasks are executed sequentially. (the util Timer has lower overhead and is more flexible but executes in its own Thread which means you will have to be a bit careful, These are solid enough imo to be used in a game, but the multithreading issues doesn't make them all that suitable for a beginner and they're far better for triggering infrequent events.

Neither Timer class give any realtime guarantees, the spec makes it entierly valid for a compliant VM to implement the Timer classes with far worse accuracy than sleep aswell.

The Timer classes also only have millisecond precision at best, (in practice it is worse than that), System.nanoTime is required to always use the most precise timer available on the underlying platform and normally has very high accuracy. (IIRC it uses QPC on Windows)

Edited by SimonForsman, 12 September 2012 - 12:56 AM.

I don't suffer from insanity, I'm enjoying every minute of it.
The voices in my head may not be real, but they have some good ideas!

#9 samoth   Crossbones+   -  Reputation: 4465

Like
0Likes
Like

Posted 12 September 2012 - 03:41 AM

Ugh... spawning an extra thread per timer to implement something that can be wrapped in one or two syscalls from the original thread on pretty much every system is really one of the dumbest things I've heard in a while. Thank you for clearing that one up. Posted Image

In that case you are of course entirely right, timers are not well suited here.

#10 SimonForsman   Crossbones+   -  Reputation: 5718

Like
0Likes
Like

Posted 12 September 2012 - 06:26 AM

Ugh... spawning an extra thread per timer to implement something that can be wrapped in one or two syscalls from the original thread on pretty much every system is really one of the dumbest things I've heard in a while. Thank you for clearing that one up. Posted Image

In that case you are of course entirely right, timers are not well suited here.


I don't think its that dumb, the util Timer class works fairly well for scheduling the execution of independent Tasks(TimerTask objects) (you can schedule multiple tasks per Timer(Allthough a timer can only execute one task at the time) and the Timer thread most likely will use the appropriate OS functions to avoid hogging the CPU while waiting (Allthough the language spec doesn't require any form of accuracy or precision so a VM could just aswell use sleep and still be compliant), The Swing Timer class is a bit more messy with its ActionListener crap but all of Swing is that way(You don't access events directly, you always create a listener(KeyListener, ActionListener, FocusListener, CaretListener, WtFListener, etc) and attach it to a UI component to handle events sent to that component) so the Swing Timer fits nicely with the rest of the API, (I really do hate Swing though and don't think it is suitable for games)
I don't suffer from insanity, I'm enjoying every minute of it.
The voices in my head may not be real, but they have some good ideas!

#11 EpicWally   Members   -  Reputation: 282

Like
0Likes
Like

Posted 12 September 2012 - 06:30 AM

Thank you all for the input! I had the oportunity to speak to a friend of mine last night who programs for a living (not in game design.) He said the root of the problem is because of Java's garbage collect system, there really isn't a good way to create a real-time system in Java, as you can't know, or control when garbage collection will happen. (You can control it to some extent, by limiting the instantiation of objects where possible.) His opinion was that using a single thread, with a variable sleep durration would be the cleanest, and most consistent you could get, at least within Java. (Not accounting for tools available in other APIs.)

#12 SimonForsman   Crossbones+   -  Reputation: 5718

Like
1Likes
Like

Posted 12 September 2012 - 07:56 AM

His opinion was that using a single thread, with a variable sleep durration would be the cleanest, and most consistent you could get, at least within Java. (Not accounting for tools available in other APIs.)


I'd recommend against it, Sleep does two things in Java:
1) It lets the underlying OS schedule another process or thread to run, your sleep duration is a minimum time for the OS to wait before considering your thread again (it can wait much, much longer and on a Desktop OS it frequently will) (on Android it doesn't apply, Android runs exactly one foreground process at the time and the scheduler will prioritize its threads which makes sleep accurate enough to use for this purpose (and on mobiles you really don't want to use more CPU than necessary since the battery is so small)
2) It triggers garbage collection (Which can also cause things to take longer than you'd expect).

The best way to avoid garbage collection is to:
1) Don't sleep in the main thread during gameplay and don't drop any references unless you can't avoid it. (This will prevent the GC from running most of the time)
2) Once you enter a loadscreen(or some other point where you can afford having the gc run), create an empty Object, create a weak reference to it then drop all references you wish to clean up, set the empty object to null then enter a loop that calls System.gc() followed by Thread.sleep(1) until calling .get() on the weak reference returns null (The weak reference will return null once the GC has destroyed the empty object you created).

The big problem with Sleep is not related to Java, it is related to desktop operating systems, the problem with sleeping in games occur regardless of what language you're using, you will always get a better gameplay experience if you hog the CPU(Which is what most games are doing). (The GC prefering to run while your thread is sleeping is actually a good thing with Java, the fact that you're sleeping means that you should be able to take the performance hit at that time (if you can't take a performance hit, don't sleep)

If you sleep on Windows(regardless of language) what will happen is:

1) Your thread stops running and the OS Scheduler starts, it will select another thread to run (out of those waiting for a turn on the CPU)
2) That thread will then run until a timer interrupt causes the scheduler to run again, on Windows this happens roughly every 16ms allthough you can force it to run more frequently with some native code (which isn't really recommended since it degrades overall system performance, more time spent scheduling rather than running applications) or until it decides to sleep. (Multicore cpus lets the OS schedule multiple threads to run at the same time which reduces the severity of this issue slightly but users also tend to have far more applications active in the background aswell)

This means that if a non sleeping thread gets scheduled after you call sleep your thread will have to wait atleast 16ms before it can run again, even if you ask to sleep for 1ms. in the worst case it won't pick your thread again the next time it runs either) and the delay can go up even higher.

and finally 3)
Your thread gets swapped back in, but since the CPU core your thread was using have been used by another thread almost nothing of what your thread was doing will be in the CPU cache which means you can look forward to some very expensive cache misses which further degrades performance. (Your thread might not even end up on the same CPU core as before the sleep).

So: for a game running in fullscreen, just hog the CPU , your game is the most important thing running on the system, add a powersaving option that the user can enable if they want to conserve their battery on a laptop or tablet. just put something like: if (powersavingEnabled) { Thread.sleep(1); } at the end of your game loop (a 1ms sleep per frame is usually enough to cause a modern CPU to clock down and save power) and then use an accurate system timer to decide if the update method should run or not.
The OS will still run the scheduler every ~16ms and might swap out your thread anyway but it will be far less common and on a multicore system the OS scheduler should be smart enough to leave a CPU hogging thread alone as long as it has other cores that it can run its less important stuff on)

Edited by SimonForsman, 12 September 2012 - 07:59 AM.

I don't suffer from insanity, I'm enjoying every minute of it.
The voices in my head may not be real, but they have some good ideas!

#13 SuperVGA   Members   -  Reputation: 1118

Like
0Likes
Like

Posted 12 September 2012 - 12:38 PM

Depending on your application and intended host system, it's actually ok to use sleep(). Sometimes it's unwise to do so, for instance if you're exhausting the cpu time of the system while wanting a higher framerate.
On the other hand, if you're certain that you don't need more game loop cycles than 1000/sleep_time_ms, you can go right ahead.
This will save battery and allow the os schedhuler to give other processes more cpu time.
For most fullscreen applications, the performance is so important that the main thread is never put to sleep().

As for the timing bit, keep that entirely seperate of sleep() . Don't rely on sleep() to set behaviour at an intended speed. Create a multiplier to all moving and animating things, which is set to the estimated framerate (avoiding spikes by smoothing and precalculating) relative to a preset, "denominating" framerate.

Mrs. Pac man made for 30fpson my machine yields approx 1730fps, so i would multiply the speed of all graphical change by 30/1730.

If you're making a multiplayer game, keep in sync with the host at specific intervals, yielding the multiplier which can then be interpolated up or down gradually.

I hope I'm making sense. :)

#14 Verik   Members   -  Reputation: 260

Like
0Likes
Like

Posted 12 September 2012 - 04:48 PM

There is a great article that discusses how operating system clocks interact with Java methods, specifically System.currentTimeMillis(), Thread.sleep() and System.nanoTime(). The article claims that the Windows system clock (of modern Windows version) can trigger threads at 15 (16?) ms intervals, but can also be forced to work in 1ms intervals. I have not verified this, but I have seen System.currentTimeMillis() report jumps of 15 ms, instead of the expected 1 ms.

My personal experience is with the JGame library which uses an advanced version of the one that EpicWally suggests. (You can look up the main game loop is located in the JGEngine class in the JRE platformversion). One of the things they do is add a Thread.yield() in case there is no time left to sleep away with a Thread.sleep(). The demo games run very smoothly, but I guess you can hardly call them taxing.

Hogging the CPU with your main thread seems like an odd idea, since you will most likely be running at least a GUI thread next to your main game thread. You really do want the GUI thread to be able to paint your frame, and grab some input events while it's at it. Even worse: your OS can always interrupt your thread regardless of whether you call Thread.sleep() or Thread.yield(). Although I have not tested this, I would expect to have a smoother frame rate if you actively give up the cycle's you don't need to other processes. Rather than waiting for the OS to decide when it time for other processes to get a share of the pie (while you were in the middle of rendering a complex frame). In the presence of multiple cores this might play out differently, but I would not know of a way to have the GUI thread hog a core ;)

Edit: minor erata

Edited by Verik, 12 September 2012 - 04:50 PM.





Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS