I have a Threaded timer that fires every second and updates a clock, the problem is that sometimes the clock will appear to be unstable and it can jump 2 seconds instead of a steady 1 second increment.
The problem of course is that the initial (or subsequent) timer is not triggered at exactly 0:000 seconds and therefore it is possible that updates to the clock appear to jitter.
Is there any way of preventing this ?
from threading import Timer
def timer():
Timer(1.00, timer).start()
STAT['ftime'] = time.strftime("%H:%M:%S")
start_time = time.time()
interval = 1
for i in range(20):
time.sleep(start_time + i*interval - time.time())
# do a thing
Replace '20' with however many seconds you want to time.
There are various approaches how to schedule, some designs may even provide measures to be able to deliver some acceptable kind of remedy for a blocked / failed initiation on a planned scheduling time-line -- what may help is finer timing / hierarchical timing / external synchronisation / asynchronous operations.
Without more details, there would be a poor practice to "recommend", but one may get ispired:
if RealTime constraints allow to bear a bit more overhead, one may go to a "supersampled" elastic, failure-resilient scheduling scenario, so as to avoid a 2 second gap ( in case of a failed one .Timer() initiation ), where threading.Timer() model fires each 50 msec, and an embedded logic decides, if it is the right-time ( not farther than a half of one scheduling interval from an idealised one second edge ) and does the real-job, that was intended to be run, or just return, in case the RTC is not "near" the planned idealised scheduling time.
a good python design also cannot forget about problems with GIL-lock issues, with avoiding blockingIO(s), with implementing a reasonable task-segmentation for CPU-bound parts of the code
Related
I want to measure the time delay of a signal. To do that the signal is put on a speaker an the delay when it gets captured by a microphone is estimated. The delay is expected to be in the range of milliseconds, so it is crucial to start the speaker signal and the measurement at the exact same time.
My question is if that can be achieved by using threads:
def play_sound():
# play sound
def record():
# start recording
if __name__ == '__main__':
t1 = threading.Thread(target=play_sound())
t2 = threading.Thread(target=record())
t1.start()
t2.start()
or is there a better way to d it?
I would start the recording thread first and look for the first peak in the signal captured by the mic. This will tell you how many ms after recording started the first sound was detected. For this you probably need to know the sampling rate of the mic etc- here is a good starting point.
The timeline is something like this
---- recording start ------- playback start -------- sound first detected ----
You want to find out how many ms after you start recording a sound was picked up ((first_peak - recording_start) in the code below), and then subtract the time it took to start the playback ((playback_start - recording_start) below)
Here's a rough code outline
from datetime import datetime
recording_start, playback_start, first_peak = None, None, None
def play_sound():
nonlocal playback_start
playback_start = datetime.now()
def record():
nonlocal recording_start, first_peak
recording_start = datetime.now()
first_peak = find_peak_location_in_ms() # implement this
Thread(target=record()).start() # note recording starts first
Thread(target=play_sound()).start()
# once the threads are finished
delay = (first_peak - recording_start) - (playback_start - recording_start)
PS one of the other answers correctly points out that you need to worry about the global interpreter lock. You can likely bypass it by using c-level APIs to record/play the sound without blocking other threads, but you may find Python's not the right tool for that job
It won't be 100% concurrent real-time, but no solution for desktop will ever be. The question then becomes if it is accurate enough for your application. To know this you should simply run a few tests with known delays and see if it works.
You should know about the global interpreter lock: https://docs.python.org/3.3/glossary.html#term-global-interpreter-lock. This means that even on a multicore pc you code won't run truly concurrent.
If this solution is not accurate enough, you should look into the multiprocessing package. https://docs.python.org/3.3/library/multiprocessing.html
Edit: Well, in order to truly get them to start simultaneously you can't start them sequentially after each other like that. You need to use multiprocessing, create the two threads, and then create some kind of interrupt that will start the two threads at the same time. And I think even then you can't be truly sure they will start at the same time because the OS can switch in other stuff (multitasking), and even if that goes fine in the processors itself things might be reordered differently, different code might be cached, etc. On a desktop you can never have the guarantuee that two programs start simultaneously. So the question then becomes if they are consistently simultaneous enough for your purpose. To answer that you will need to find someone with experience in this, or just run a few tests.
I'm wondering how accurate python's time.sleep() method is for longer time periods spanning from a few minutes up to a few days.
My concern is, that there might be a drift which will add up when using this method for longer time periods.
Alternatively I have come up with a different solution to end a loop after a certain amount of time has passed:
end = time.time() + 10000
while 1:
if time.time() > end:
break
This is accurate down to a few milliseconds which is fine for my use case and won't drift over time.
Python's time.sleep() function is accurate and should be used in this case as it is simpler and easier to run. An example is
time.sleep(10000) # will stop all running scripts in the same pid
Using a bare while statement without any threshold will use a lot of your resources, which is why you should use a time.sleep expression to reduce this. You also should have used the while statement condition statement as this will make sure your while statement closes.
As shown below
end = time.time() + 10000
while end > time.time(): # ensures to end when time.time (now) is more than end
time.sleep(0.001) # creates a 1 ms gap to decrease cpu usage
I would recommend using the pause module, you can get millisecond precision over a period of days. No need to roll your own here.
https://github.com/jgillick/python-pause
Python's time.sleep() is accurate for any length of time with two little flaws:
The time t must be considered "at least t seconds" as there may be a
number of system events that are scheduled to start at the precise moment
"time when started" + t.
The sleep may be interrupted if the signal handler raises an exception.
I think, but am not certain, that these flaws are found in most programming languages.
I have a scheduling function and a scheduler with a queue of future events ordered by time. I'm using UNIX timestamps and the regular time.time(). One fragment of the scheduler is roughly equivalent to this:
# select the nearest event (eventfunc at eventime)
sleeptime = eventtime - time.time()
# if the sleep gets interrupted,
# the whole block will be restarted
interruptible_sleep(sleeptime)
eventfunc()
where the eventtime could be computed either based on a delay:
eventtime = time.time() + delay_seconds
or based on an exact date and time, e.g.:
eventtime = datetime(year,month,day,hour,min).timestamp()
Now we have the monotonic time in Python. I'm considering to modify the scheduler to use the monotonic time. Schedulers are supposed to use the monotonic time they say.
No problem with delays:
sleeptime = eventtime - time.monotonic()
where:
eventtime = time.monotonic() + delay_seconds
But with the exact time I think the best way is to leave the code as it is. Is that correct?
If yes, I would need two event queues, one based on monotonic time and one based on regular time. I don't like that idea much.
As I said in the comment, your code duplicates the functionality of the sched standard module - so you can as well use solving this problem as a convenient excuse to migrate to it.
That said,
what you're supposed to do if system time jumps forward or backward is task-specific.
time.monotonic() is designed for cases when you need to do things with set intervals between them regardless of anything
So, if your solution is expected to instead react to time jumps by running scheduled tasks sooner or later than it otherwise would, in accordance with the new system time, you have no reason to use monotonic time.
If you wish to do both, then you either need two schedulers, or tasks with timestamps of the two kinds.
In the latter case, the scheduler will need to convert one type to the other (every time it calculates how much to wait/whether to run the next task) - for which time provides no means.
I want to set multiple alarm in python. What is the recommended way of setting it up? My use-case is that I've threshold time for N variables. When the current time reaches the threshold value, I want all the variables with that threshold values.
Here's my apprach:-
threshold_time_list = [get list all times from the DB]
current_time = datetime.now()
[i for i in threshold_time_list if i==current_time]
But this is very inefficient way of doing it since I might have 250+ variables like a/b/c.
And also I have to check this condition every second(cronjob). Is there a better way of doing it?
I found on SO, this can be done using threading and making the thread to go to sleep for threshod - current_time. But running 250 threads parallely is again an issue, since I've been facing an issue in my production where Django gets hanged (dont know why) and I need to restart the server to make it work again. We're asssuming that Django might get out of threads for processing, hence making 250 more threads is cumbersome.
Also if someone knows , why does Django gets hang in b/w the running live product it will be beneficial.
Can this alarm question be done in celery?
Use the sched module. This lets you create any number of scheduled tasks, then run them when they kick off, one at a time.
For example, if I do time.sleep(100) and immediately hibernate my computer for 99 seconds, will the next statement be executed in 1 second or 100 seconds after waking up?
If the answer is 1 second, how do you "sleep" 100 seconds, regardless of the length of hibernate/standby?
time.sleep(N) attempts to sleep at least N seconds of elapsed, AKA "wall-clock" time - of course there can be no guarantee that the sleep will last exactly N seconds; for example, the thread becomes ready to execute again at that time, but it cannot necessarily preempt whatever other thread is executing at that time -- that's the operating system's decision to make, not any programming language's; on the other hand, sleep may be prematurely interrupted by various kinds of events (such as interrupts).
If you can find on your operating system some clock-like thingy that only advances when the system's state is the one you care about (e.g. "not hybernated", in your case), then of course you can go back to sleep if you wake up again "too early".
For example, on Windows 7, QueryUnbiasedInterruptTime is specifically documented to "not include time the system spends in sleep or hibernation" and to use units of 100 nanoseconds. So if you call that, e.g. through ctypes, you can achieve the effect you want:
def unbiasedsleep(n):
start = kernel32.QueryUnbiasedInterruptTime()
target = start + n * 10 * 1000 * 1000
while True:
timeleft = target - kernel32.QueryUnbiasedInterruptTime()
if timeleft > 0:
time.sleep(timeleft / (10 * 1000 * 1000.0))
I don't know how to get the equivalent of QueryUnbiasedInterruptTime on other releases of Windows or other operating systems, but then, you don't tell us what operating system(s) you're interested in, so it would be pretty pointless anyway to present a long laundry lists of approaches which may work similarly in different environments.
I don't know exactly what you are trying to achieve, but
for i in range(100):sleep(1)
might work, as the hibernate would only use up to 1 seconds worth of the sleep
Clearly, you must sleep according to real, elapsed time.
The alternative (sleeping according to some other clock that "somehow" started and stopped) would be unmanageable. How would your application (which is sleeping) be notified of all this starting and stopping activity? Right, it would have to be woken up to be told that it was not supposed to run because the system was hibernating.
Or, perhaps, some super-sophisticated OS-level scheduler could be used to determine if some time the system was "busy" vs. "hibernating" counted against the schedules of various sleeping processes.
All too complex.
Indeed, if you check carefully, sleep is pretty approximate and any Unix Signal will interrupt it. So it's possible to wake early for lots of reasons. Control-C being the big example.