I need to run my game loop with very accurate timing. I am trying to use NSTimer to do this, and I am getting ok results, but there is a bit of drift.
When NSTimer fires does the next time event start counting when the handler finishes or does it start counting straight away.
If the former is it reasonable for me to use setFireDate to try to offset the next timer firing - when I tried this things seemed worse.
My timer is set to fire every 44ms and I would like to stop it drifting by more than 20ms. If it does drift I would like to correct it for the next fire.
Is this a reasonable thing to try and do with NSTimer?
I don't think NSTimer will give you "very" accurate timing. It fires on the run loop, so if it's in your main thread then it'll get delayed by everything from UI updates to event handling.
You might try creating a thread and scheduling your timer on that thread's run loop. Having that timer as the only thing on that run loop should limit the number of things that can interfere with it.
If that doesn't work, well, you'll already have it working on a thread, so you may as well switch to a usleep() loop.
Also keep in mind that the NSTimer documentation states:
Because of the various input sources a
typical run loop manages, the
effective resolution of the time
interval for a timer is limited to on
the order of 50-100 milliseconds. If a
timer’s firing time occurs while the
run loop is in a mode that is not
monitoring the timer or during a long
callout, the timer does not fire until
the next time the run loop checks the
timer. Therefore, the actual time at
which the timer fires potentially can
be a significant period of time after
the scheduled firing time.
Related
I am struggling to understand the key differences between DispatchSourceTimer, Timer and asyncAfter (in my case for scheduling a task that needs to be ran every X seconds, although understanding the differences in timers can be useful to) (Or is there another (more efficient) scheduling mechanism in Swift besides the listed timers?).
A Timer needs an active run loop on the current queue it was started on. A DispatchSourceTimer does not need that. A Timer keeps the CPU from going into the idle state. Does this apply to DispatchSourceTimer/asyncAfter as well?
In what situation a Timer is preferred over a DispatchSourceTimer/asyncAfter? And of course the difference between all of them?
I want to schedule work every 15 seconds in my application on a private queue. This means I have to use DispatchSourceTimer because I am on a queue that is not the main thread (or add a runloop to the queue and use Timer). However, I do not see any benefit of even using a Timer in the first place. Maybe there is another operation that I can use that schedule work every X seconds on a private queue that is more efficient than a DispatchSourceTimer, but I did not came across a better solution.
Is a DispatchSourceTimer more efficient than a Timer? Or should I go on a self-calling method with asyncAfter?
This is the code to create the timers.
asyncAfter
DispatchQueue.global().asyncAfter(deadline: .now() + .seconds(2)) {
// Code
}
Timer
Timer.scheduledTimer(withTimeInterval: 1, repeats: false) { (_) in
// Code
}
DispatchSourceTimer
let timer = DispatchSource.makeTimerSource()
timer.schedule(deadline: .now() + .seconds(1))
timer.setEventHandler {
// Code
}
timer.activate()
Whats are the cons and pros of all the timers? When should I use one above the other? What timer way is the most efficient? I came up with the following:
Timer
Pros:
Can be invalidated
No reference needed
Can be stopped while it is scheduled.
Cons:
Prevents CPU to go idle
Needs to be run on a queue with a run loop (else nothing happens, even no assertion trigger...)
DispatchSourceTimer
Pros:
Can be cancelled
No run loop needed
Cons:
Needs a strong reference else it gets deallocated instantly
asyncAfter
Pros:
- No run loop needed
Cons:
- Can not be cancelled (I think)
Are there even more timers? Why are there so many timers? I expected some real difference across all the different timers, but I couldn't find them.
Alot of questions here as you can read. The main question is: what timers are available and what timers should I use in what case and why?
Timer is a Swift bridge of NSTimer, which goes back to NeXTSTEP, long, long before Grand Central Dispatch (GCD) and things like DispatchSourceTimer, which didn't come along until 10.6 (in the form of dispatch_source_set_timer) and dispatchAfter (in the form of dispatch_after).
NSTimer is based on the run loop, which was the primary way that concurrency was done until GCD. It's a cooperative concurrency system, designed primary to run on a single thread on a single core (though it can be expanded to multi-threaded environments).
While the run loop is still very important in Cocoa, it is no longer the primary, or even preferred, way to manage concurrency. Since 10.6, GCD has been the increasingly preferred approach (though adding a block-based NSTimer API in the 10.12 timeframe was a welcome modernization).
On the scale of 15 seconds, the efficiency differences are pretty irrelevant. That said, I don't understand your comment "A Timer keeps the CPU from going into the idle state." I don't believe that's true. The CPU will definitely still go into the idle state when waiting on an NSTimer to fire.
I would not set up a run loop just to run an NSTimer. You would be much better off scheduling it on the main runloop and then using DispatchQueue.async to do the actual work on some other queue.
As a broad rule, I use the highest-level tool that meets the need. Those are the ones that Apple is likely to optimize the best over time with me making the fewest changes. For example, NSTimer fire dates are automatically adjusted to improve energy efficiency. With DispatchSourceTimer, you get control over the leeway setting to get the same benefit, but it's up to you to set it (the default is zero, which has the worst energy impact). Of course, the reverse is also true. DispatchSourceTimer is the lowest level and gives you the most control, so if that's what you need, that's the one to use.
For your example, I'd personally probably use a Timer and just dispatch to the private queue as part of the block. But a DispatchSourceTimer would be completely appropriate.
asyncAfter is really a different thing, since it's always a one-shot. That's great if you want a one-shot, but it changes things if you want to repeat. If you just call asyncAfter in the block to repeat, it's going to be 15 seconds after the last time you finished, rather than being spaced 15 seconds apart. The former will tend to drift a bit late over time. The design question is this: if for some reason your task took 5 seconds to complete, would you want the next fire event to happen 15 seconds from the end of that, or would you want a constant 15 seconds between each fire event? Your choice there will determine which tool is correct.
As a slight note there, NSTimer events are always a little later than they are scheduled. GCD events with a leeway setting can be a little early or a little late. As a practical matter, there's no such thing as being "on time" (that's a period of zero length; you're not going to hit it). So the question is always whether you are promised to be late like NSTimer, or you might be early like GCD with leeway.
If you don't use cocoa2d etc., how would you control the speed of a frame if you had to code this manually?
i.e. if you wanted things to operate in 50 frames per second (or whatever the industry best practice is?)
use CADisplayLink to get called at every frame. It will be max 60 FPS. If your code do too much work, you'll be called less often, and your UI will feel slow below 40 FPS.
Alternative is to schedule NSTimers, but it has some issues. If your runloop is not ready to call the timer on time, calls will be skipped, thus not guaranteeing any frame rate.
from apple's doc
A repeating timer always schedules
itself based on the scheduled firing
time, as opposed to the actual firing
time. For example, if a timer is
scheduled to fire at a particular time
and every 5 seconds after that, the
scheduled firing time will always fall
on the original 5 second time
intervals, even if the actual firing
time gets delayed. If the firing time
is delayed so far that it passes one
or more of the scheduled firing times,
the timer is fired only once for that
time period; the timer is then
rescheduled, after firing, for the
next scheduled firing time in the
future.
I have a requirement in my app which requires me to display some message to the user if there is no activity happening for about 3 hours on the app/ipad.
I considered the solution of having an NSTimer that would start at launch. If the user performs any action, I invalidate the timer and start a new one. However, there is video playback on the app and for all I know, the user may be watching the video for about 3 hours and performs no other action during that time and would still get the message.
So, an alternative is to invalidate and start the timer every time I detect the ipad/iphone has moved. In other words, use the accelerometer and in the call back to detect acceleration, I can invalidate and create the timer again.
But my worry with this approach is that even for smallest of movements, the timer would have to be invalidated and recreated. Will this approach in any way impact performance?
Thanks and Regards,
hetal
Creating a timer is not that expensive, but it's still a little expensive.
The good news is that you can arbitrarily change the fire date:
[timer setFireDate:[NSDate dateWithTimeIntervalSinceNow:3*60*60]];
Alternatively, for very slightly less overhead:
CFRunLoopTimerSetNextFireDate((CFRunLoopTimerRef)timer, CFAbsoluteTimeGetCurrent()+3*60*60);
(I think the CFAbsoluteTimeGetCurrent() overhead is more than the object-creation overhead, but meh.)
A slightly better solution might be to leave the timer alone most of the time; simply update the "last activity" timestamp. When the timer fires, look at the "last activity" timestamp. If it's more than 3 hours ago, thenshow the notification. If it's less than 3 hours ago, then set the next fire date appropriately; this means the timer fires (on average) at most every 1.5 hours, which is probably not as costly as repeatedly changing the fire-date.
See mach_absolute_time() for a relatively low-overhead timebase (pre-calculating what 3 hours is in mach_absolute_time units). It still takes about 3 microseconds, which is practically forever (1000 clocks cycles!).
If you're really worried about overhead, simply set an "activity" flag every time something happens, and use (e.g.) a 1 hour timer. When the timer fires, do something like if (activity) {counter = 0; activity = 0; } else { counter ++; if (counter == 3) { ... } }. It's debatable whether a couple of microseconds here and there are more costly than a timer firing every hour, but they're both pretty negligible.
The far bigger problem is that the accelerometer eats power and CPU time (and delivering updates takes CPU time). Setting updateInterval = 10 or so will reduce the overhead, and it's capped to a sensible value (around 1 s) by the OS.
Apple has a feature in multitasking that they call "Task finishing" use by - (UIBackgroundTaskIdentifier)beginBackgroundTaskWithExpirationHandler:(void(^)(void))handler
Found here and more stuff here
Can't you just send a message to your NSTimer whenever a video starts, to invalidate the timer? Then when the movie ends, start the timer back up.
Say I have two NSTimers in my iPhone app: timer1 and timer2. timer1 calls function1 30 times per second and timer2 calls function2 30 times per second. Assume these two functions are reading and updating the same integer variables. Are there any "multi-threading" issues here? If not how does iPhone OS handle the execution of the two functions (in general)?
The core of any iPhone application (and some other platforms) is a run loop. Each thread may have a run loop, and the run loop on the main thread is set up for you. When there is something to do, like fire an NSTimer or draw the view hierarchy, the run loop performs those tasks. When there is nothing to do, the run loop is idle, allowing other things to process.
The run loop internals are thread aware so that nothing handled by the run loop has to be. All the NSTimer callbacks and view rendering happens on a single thread in a serial or linear flow.
For specific details, you can look up NSRunLoop or CFRunLoop.
As far as I'm aware, NSTimers use the run loop to achieve their 'asynchronosity'. If the timer is created using the scheduledTimerWith... method then it will be scheduled on the default (main) run loop and will be executed on the main thread.
I don't think any new threads are created for the timer (unless you do it explicitly, and assign the timer to that run loop).
So in the end, I believe your two timers shouldn't conflict with each other.
However, the documentation states that timers don't represent real time. The timer will fire on or after the scheduled time, but is not guaranteed to fire exactly at the scheduled time. Therefore if the fired method takes longer to execute than the interval of the timer, you may not see the method called as often as you'd expect.
With that said, is there any particular reason you're asking the question? Are you seeing undesired behaviour using this setup?
I am wondering what happen if my NSTimer fires every 1 second and my function takes 2 seconds to perform the task.
Thanks for your answer.
Thierry
Is your function blocking? According to the documentation,
A timer is not a real-time mechanism; it fires only when one of the run loop modes to which the timer has been added is running and able to check if the timer’s firing time has passed. If a timer’s firing time occurs while the run loop is in a mode that is not monitoring the timer or during a long callout, the timer does not fire until the next time the run loop checks the timer. Therefore, the actual time at which the timer fires potentially can be a significant period of time after the scheduled firing time.
Therefore, your timer will not fire during the task if it is blocking.