[Python-ideas] time.Timer

Chris Angelico rosuav at gmail.com
Wed Feb 26 19:01:20 CET 2014


Yes, this is OT, but quite a bit of it is on the general subject of
threading and counters and timing, all of which are important to
Python. But if you want to continue this discussion further, we should
probably move to python-list or something.

On Thu, Feb 27, 2014 at 4:37 AM, anatoly techtonik <techtonik at gmail.com> wrote:
> On Wed, Feb 26, 2014 at 11:29 AM, Chris Angelico <rosuav at gmail.com> wrote:
>> For measuring FPS,
>> you should probably use an algorithm more like this:
>>
>> 1) Spawn an FPS counter thread, or async alarm, or something, to be
>> executed every second.
>
> I don't want to mess with woes of concurrent programming
> for this kind of accuracy. Python is good at what it is good for.
> https://stackoverflow.com/questions/134867/which-programming-language-makes-concurrent-programming-as-easy-as-possible

Threads are pretty easy. Remember, you're working with an idle thread
- it wakes up once a second to do stuff, then goes back to sleep.
That's really easy to handle: a simple while loop in a separate
function.

>> 2) Each frame, increment a counter. Never reset the counter.
>
> Although offtopic, but I don't get why resetting a counter is worse
> than storing two values and subtracting them.

Technically, it's possible for this operation to be broken in half:

frame_count += 1

If the other thread comes in between the read and the write, your next
second will have twice the apparent FPS. By restricting one thread to
read-only access, you guarantee atomicity. It's an obscure situation,
but just get into the habit of having everything written to by one
thread only, and threading is really easy.

>> 3) Every time the alarm goes off, record the current time and the
>> current frame counter.
>> 4) Your FPS is (frames - last_frames) / (time - last_time)
>>
>> That way, you query the current time roughly once a second. It's safe
>> against sleep(1) taking more than one second to return (because it
>> actually queries the time), it's safe against the FPS being extremely
>> low, and it's fairly efficient.
>
> It increases complexity, but doesn't increase accuracy, and therefore
> is fairly inefficient for maintenance. In formula:
>
> (frames - last_frames) / (time - last_time)
>
> (time - last_time) == 1

Wrong. In the first place, time.time() returns a float, so that would
be 1.0 (which means you'll get a float result, even in Py2); and in
the second place, sleeping for one second is guaranteed to pause for
at least one second, maybe more, and there's other code around it too.
So usually, you'll have a figure higher than 1.0. This is even more
pronounced if your loop waits for some other action, like the painting
of the next frame.

> so where I get 3 frames, your code will get 2. The code only makes
> sense when timer fire is delayed (I don't know if it is the case with
> threads) or when you make frame-based FPS measurements (every
> 10 frames or so).

Timer fire should always be expected to be delayed, unless you're
running on some sort of real-time system. (And even then, I don't know
how you get around the laws of physics. Maybe it could throw an
exception if the sleep lasted too long.)

It may not seem significant when you're expecting 60 FPS, but two points.

1) FPS displays are really important when something goes wrong and
you're achieving 2.5 FPS. And I have seen times when this exact thing
has happened - in fact, I've watched a game struggle through <1.0 FPS,
and its display actually couldn't handle it, which means I have no
idea how poorly it was really performing.

2) Running at exactly 60 FPS when your screen repaints at exactly 60
FPS is good. Running at 59 FPS when your screen repaints at 60 FPS is
bad. Look up Vsync and why so many games let you turn it on or off.
Misdisplaying the FPS by one could have someone toggle Vsync
inappropriately, or complain that it's not working. Showing 59.99 FPS
doesn't look too bad (and you could have your display round that
carefully).

ChrisA


More information about the Python-ideas mailing list