-3

I'm making a digital clock in python for minecraft pi edition. I'm using a single while loop that contains a lot of code - it takes a short time to execute one run of it, but it's a few milliseconds more than I want, and this is wreaking havoc on my clock. Is there a way to make a while loop completely accurate? I'm using two counts of time.sleep(1), but it's taking longer than two seconds to execute.

Example:

while True:
    start = time.time()
    for _ in range(5):
        1000**3
    time.sleep(1)
    print (time.time() - start)

Which takes more than 1 second per loop.

1.00102806091
1.00028204918
1.00103116035
1.00051879883
1.0010240078
1.00102782249

This error accumulates over time. How can I prevent it from drifting?

TemporalWolf
  • 7,727
  • 1
  • 30
  • 50
dangerscott
  • 61
  • 2
  • 9
  • 1
    Each iteration of your loop will take 2 seconds (by `time.sleep()`) + the time taken by your code in the while to execute. `time.sleep(n)` stops the execution of your code by `n` seconds – Moinuddin Quadri Nov 08 '16 at 21:34
  • How come there's so much negative feedback? What am I doing wrong? – dangerscott Nov 08 '16 at 21:58
  • 1
    Well @I.Scott one thing I see is that you have not put any code into your question. Do you always need code in a question? No not at all. But in your case, excluding code from your question may be sending the message that you want someone to write code for you, which _way_ off-topic here. If you do have some code, I suggest adding to your question to show that you have at least attempted to solve your problem. – Christian Dean Nov 08 '16 at 22:01
  • Welcome to Stack Overflow. Please take the [tour] and read [ask]. – Peter Wood Nov 08 '16 at 22:09
  • @leaf I didn't think I needed to add my code because firstly it's very long and I don't think anyone would want to read through 710 lines of python (especially from a beginner) and it's a fairly general question - I don't want poeple to write my program for me, I just wanted a more reliable of making a while loop as mine wasn't accurate enough. I explained what I was doing pretty clearly in the original question, so I don't think there's a need for adding my long program or a need to downvote my question. – dangerscott Nov 08 '16 at 22:29
  • @leaf I think the question asked doesn't really require any code, although an example would make it more clear. His specific use case isn't really relevant to the question: how to enforce a specific timing for a loop – TemporalWolf Nov 08 '16 at 23:22
  • 1
    @TemporalWolf both of you have very valid points. I was simply voicing why I think that his question is gaining downvotes. – Christian Dean Nov 08 '16 at 23:24
  • @I.Scott I added an additional edit which should trigger a reopen review. Alternatively, you can edit it yourself to add information if it doesn't currently address your question completely. – TemporalWolf Nov 09 '16 at 22:31
  • @ADyson So this closed shortly after it was edited, which leads me to believe most of the close votes were cast before the edit. Can you address reopening it? As now written, I believe it passes muster. – TemporalWolf Nov 15 '16 at 22:27

1 Answers1

8

You can write time synchronization code (this sample taken from a server monitor I have):

# sync time so that it runs every two minutes, in 20 minute cycles (:00, :20, :40)
    time.sleep(1200 - (time.time() % 1200))
    while True:
        # Do stuff
        time.sleep(120 - (time.time() % 120))

If you want to run something every two seconds:

time.sleep(2 - (time.time() % 2)) 

will make it sleep until the next even second, then run. This will work unless the time to Do stuff exceeds a cycle. It will then skip a beat.

For a clock, example output:

>>> for _ in range(5): 
...     time.sleep(1 - (time.time() % 1)) 
...     print time.time()
1478641441.0
1478641442.0
1478641443.0
1478641444.0
1478641445.0

This works because time.time() % 1 gives just the fraction of a second from the current time: 0.37 for example. When I say time.sleep(1 - 0.37) it sleeps for 0.63 seconds, which is the time remaining until the next round second.

If next time it takes 0.55 seconds to run my code, it will sleep the remaining 0.45 automatically.

TemporalWolf
  • 7,727
  • 1
  • 30
  • 50