0

I'm using wxpython and threading module of python to build a simple timer with GUI. I used time.slee(0.5) to measure the time. The problem is: Once I start the timer and switch to other program like chrome. Some times later when I switched back, the time displayed on my timer is very inaccurate. For example, if I set 3 minutes to run, it turns out that my timer is 3 times slower than the operating system clock.

After searching, I know that time.sleep() is unreliable, but it seems the gap is so huge that makes me doubt if there is something wrong.

I also noticed that If I don't put the script into background, then there is only 2-3 seconds difference.

I can accept several seconds difference, but not 2 "minutes".How can I solve it?

Zumars
  • 19
  • 3
  • 1
    You might find that checking the current time and comparing it to a predetermined time might be more accurate. – 101 Jun 03 '15 at 23:29
  • 1
    If the Sleep() time is that unreliable, your box is grossly overloaded or your design is grossly bad:( – Martin James Jun 03 '15 at 23:31
  • 2
    Because most modern desktop/server operating systems have pre-emptive schedulers you'll find that ``time.sleep()`` is not guaranteed to be very accurate; especially with other competing resources on the system. – James Mills Jun 03 '15 at 23:32
  • to avoid drift, synchronize the sleeps with a system clock. You should probably use GUI-specific timer instead e.g., [`widget.after()` in tkinter or `GObject.timeout_add()` in Gtk](http://stackoverflow.com/a/14040516/4279). See [code examples in the links](http://stackoverflow.com/questions/28528935/timing-issues-in-metronome-script-in-python-using-pygame#comment45378176_28528935). – jfs Jun 05 '15 at 10:39

2 Answers2

3

sleep() does not guarantee scheduling after the time given. It just guarantees to sleep at least this time. It can very well sleep longer, depending on system load.

Just compare against the system time from time.time (or time.clock, depends on OS - read the notes in the documentation). after wakeup and use sleep() just not to occupy the CPU all time.

Edit:

There are several ways to improve that: - If your timer has just to wakeup after the time elapsed, you could simply sleep() until short before wakeup and busy-wait for the time completely elapse. That would block the GUI/app during the timeout. Not so good.

  • You can use threading with one thread for display update at ca. 1s (or whatever you think appropriate) and another thread for the timeout as shown above. A bit complicated.

    • A third approach would to use sleep() for GUI-update without busy-wait for each second. That would give a bitt less accurate display, but less CPU performance. Short before the time elapsed, you could busy wait for the time remaining.

Ok, that much for voluntary consulting.

too honest for this site
  • 12,050
  • 4
  • 30
  • 52
  • I tried to combine time.sleep() with "busy waiting" and even pure busy waiting. Both of them will lead to a 20-25% cpu usage Once I start the timer. Is there any way to improve its performance? – Zumars Jun 05 '15 at 02:07
  • @Zumars: The better (and correct) way might be to use threading. But the accuracy is still not much better - for the same reasons as for sleep(). Actually, that would do the same call. Hmm... I edited my answer, my good deed today. – too honest for this site Jun 05 '15 at 02:26
0

Finally I solved this problem by using event.wait() and multiprocessing module with good resolution and low cpu usage.

Zumars
  • 19
  • 3