Python command to run on every 45th second - python

How do i make the the program run every time the timestamp in seconds is 45, currently I am using time.sleep, but my run time tends to vary a little bit every time the program is executed and i would like it to execute again if the timestamp is on the 45th second. Currently I have something like this where the run loop commences every 60 seconds, however I would like it to run the loop when the timestamp seconds slot == 45
def run_loop(self):
while True:
sys.stdout.write("-----\n")
sys.stdout.flush()
start = time.time()
self.takeProfit()
self.place_orders()
end = time.time()
print("runtime is ", end - start)
sleep(60)
def run():
# Try/except just keeps ctrl-c from printing an ugly stacktrace
ei = ExchangeInterface()
try:
ei.run_loop()
except (KeyboardInterrupt, SystemExit):
sys.exit()
ExchangeInterface.run()
My run time at the moment tends to be around 18-20 seconds

You could use the datetime module, and check if datetime.now().second == 45.
E.g.
from datetime import datetime
if datetime.now().second == 45:
do_stuff()
In your case you would use some logic to check every X amount of time if we are at the 45th second.

So I assume you specifically mean run an event at the 45-th second of the minute?
That sounds like you want to do event scheduling:
https://docs.python.org/3/library/sched.html
In the example on that page, they only use the enter method of the scheduler and not enterabs, which is what you should be using.
For that, you need to figure out the time that's at 45 seconds from the current minute. Some simple math gives that:
t = time.time()
minute = 60 * (t \\ 60) #Use integer division!
s.enterabs(minute + 45, ...)
s.run()
The stuff inside the ... specifies what you want to run/schedule, just read up on the package doc to figure out the format.
Then just put that scheduling into your loop and it should all be good, and no need for the sleep(60) no more.

Related

Python - Pause entire script every 10 minutes

Need a way to pause a script for 2 minutes after letting it run for 10 minutes first, and then have this process repeat itself. I need the script itself to continue running throughout the 10 minutes.
I tried using threading but found that it didn't actually pause the the rest of the script.
EDIT: Added code to give perspective. Hopefully this helps to explain my issue.
Your code has a nice loop where you can implant the pause, like so:
from datetime import datetime, timedelta
...
def start():
lastsleep = datetime.now() # <-- new
while True:
openBank()
gear()
invCheck()
timer = random.uniform(33, 37)
print("Sleep time: %s" % timer)
time.sleep(timer)
if (datetime.now() - lastsleep) > timedelta(minutes=10): # <-- new
time.sleep(2*60)
lastsleep = datetime.now()
Note that this will not sleep exactly after 10 minutes, but whenever 10 minutes are over and it reaches the checkpoint. This may be 10:12 or 13:47 minutes, depending on what the other code (openBank(), gear() etc.) does before.
Answer before code was shown:
The problem is: we have no information on how your code looks like.
If you have
something = getSomething()
something.DoSomeVeryExpensiveOperation() # takes 25 minutes
there's no good way to interrupt or pause that method after 10 minutes.
The only way I can think of as a generic method is like this:
use multiprocessing
monitor the process from outside
after 10 minutes, suspend all threads of the process
sleep 2 minutes
resume all threads of the process
Before you do that, you should know why you should never suspend a thread

How to loop a function to perform a task every 15 minutes (on the 0/15/30/45 minute mark)?

I have a program running on a Raspberry Pi, and I want to pull some data from a thermometer every 15 minutes at 0, 15, 30 and 45 minutes past the hour.
I have tried this using a while loop, I previously used time.sleep(900) effectively, but this sometimes drifted away from 0, 15, 30 and 45 minutes past the hour.
At the moment I currently have this;
from datetime import datetime
def run(condition):
while condition == True:
if (datetime.now().minute == (0 or 15 or 30 or 45)):
#perform some task
temperature_store()
For sake of simplicity I have not got into what temperature_store() does, but it reads the temperature from a sensor plugged into the Pi and then prints it.
I want temperature_store() to occur every 15 minutes, but currently, it is happening every second.
I am aware that it is probably because I have the logic/syntax of the while loop wrong, but I cannot figure it out. (Do not have much experience with python scripts and delays in time).
There's two ways to do this: the 'easy' way, and the stable way.
The easy way is simply to do the following:
from datetime import datetime
from time import sleep
def run(condition):
while datetime.now().minute not in {0, 15, 30, 45}: # Wait 1 second until we are synced up with the 'every 15 minutes' clock
sleep(1)
def task():
# Your task goes here
# Functionised because we need to call it twice
temperature_store()
task()
while condition == True:
sleep(60*15) # Wait for 15 minutes
task()
This essentially waits until we are synced up with the correct minute, then executes it, and simply waits 15 minutes before looping. Use it if you wish, it's the simplest way in pure Python. The issues with this are countless, however:
It syncs up with the minute, not the second
It's machine dependent, and may give incorrect readings on some machines
It needs to run continuously!
The second method is to use cron-jobs, as suggested in the comments. This is superior because:
It uses system-level events, not timers, so we can assure the best possible accuracy
Since we're not waiting, there's no room for error
It only runs the function once it gets the aforementioned event setter.
So, to use, simply (assuming you're on Linux):
from crontab import CronTab
cron = CronTab(user='username') # Initialise a new CronTab instance
job = cron.new(command='python yourfile.py') # create a new task
job.minute.on(0, 15, 30, 45) # Define that it should be on every 0th, 15th, 30th and 45th minute
cron.write() # 'Start' the task (i.e trigger the cron-job, but through the Python library instead
(obviously, configure username appropriately)
In yourfile.py, in the same path, simply put your code for temperature_store().
I hope this helps. Obviously, go with the first methods or even the suggestions in the comments if you prefer, but I just felt that the entire loop structure was a bit too fragile, especially on a Raspberry Pi. This should hopefully be something more stable and scalable, should you want to hook up other IoT things to your Pi.
I did the module test in case of the program that prints seconds every 15 seconds.
The below code does not contain sleep().
You can change second to minute in below code to do tasks every 15 minutes.
from datetime import datetime
while True:
a = datetime.now().second
if (a % 15) == 0: # every 15 seconds
print(a) # ---- To do something every 15 seconds ---- #
while True: # discard any milliseconds or duplicated 15 seconds
a = datetime.now().second
if (a % 15) is not 0:
break
But I think that cron or any other schduler modules are good choices.
I have come up with the following answer, using some of the logic from #geza-kerecsenyi 's answer
def run():
first = True
while first == True:
second = True
while second == True:
if datetime.now().minute == 0 or datetime.now().minute ==15 or datetime.now().minute ==30 or datetime.now().minute == 45:
action()
sleep(899)
I am not sure which of these is better in terms of CPU or which is more effective to run, but the logic seems sound on both.
[#geza-kerecsenyi will mark your answer as correct]

I have some code and I would like some troubleshooting on it

My timer won't work properly, since it keeps printing forever, not what I want.
I've already tried re-organizing the script in many ways, but the result is always the same.
import time
CommandInput = input()
#execution [uptime]
def uptime(y):
while 1 == 1:
if (CommandInput == "uptime"):
print(y, " seconds")
y = y + 1
time.sleep(1)
uptime(9)
I wanted to make some sort of "background timer" that kept running from when the script was executed up to when it was closed, and if I typed a certain line in the input it would show the current number it is in. The problem is that it keeps printing the timer forever, for every single number it counts. I wanted to do a one-time thing, where you could wait as much as you want and type the input, which would show the number the timer is in.
Your current program has to wait for input() to finish. The compiler does not move past the second line until the user hits enter. Thus the functions starts once the input is finished.
This timer could be done several way, such as threading or timers. There are some examples of that here and here. For threading, you need one process for user inputs and one for timers. But the better and easier way is to to use a timer and store the current time. I believe the following code is somewhat similar to what you want:
import time
start_time = time.time()
def get_time():
current_time = time.time()
total = current_time - start_time
return total
while True:
CommandInput = input()
if CommandInput == "uptime":
y = get_time()
print(str(round(y)) + " seconds")
The variable start_time records the current time at the start. time.time() gets the current time in seconds on the computer. The get_time function is called after an input and sees how much time has pasted by subtracting the current time minus the start time. This way the you do not need multiple loops.
The while True loops just waits for the user input and then prints the time. This then repeats until the program is exited.
To write a script like that you would need to look into a module called asyncio (https://docs.python.org/3/library/asyncio.html), which would allow you to run multiple things at the same time.
Here is a asyncio hello world:
import asyncio
async def main():
print('Hello ...')
await asyncio.sleep(1)
print('... World!')
# Python 3.7+
asyncio.run(main())

Can i set a threading timer with clock time to sync with cron job in python

I have a cron job that runs at 12, 12:30,1, 1:30. So every half hour intervals on the clock. I want to run a thread in my python code whenever the cron job runs.
I have seen examples where to run a timer every x seconds/mintues.But if I start my python code at 1:15pm for example if I set a timer for every 30 mins, the next time it will run is at 1:45pm. I want to thread to run at 1:30pm though. Is that possible?
Almost everything is possible, the real question is why do you want to do this? Keep in mind that cron scheduler won't necessarily execute jobs at precise times and furthermore, checking the time in Python won't necessarily correspond to cron's time, so if you need to execute something in your Python code after a cron job is executed, you cannot rely on measuring timings in Python - you actually need to 'communicate' from your cron job to your Python script (the easiest would be using datagram sockets)
But, if you want to simulate cron scheduler in Python, one way to do it is to use the datetime module to get the current time and then calculate the amount of time.sleep() you need before your command fires again, e.g.:
def schedule_hourly_task(task, minute=0):
# get hourly offset in seconds in range 1-3600
period = ((60 + minute) % 60) * 60 or 3600
while True:
# get current time
current = datetime.datetime.now()
# count number of seconds in the current hour
offset = (current - current.replace(minute=0, second=0, microsecond=0)).total_seconds()
# calculate number of seconds til next period
sleep = period - offset % period
if offset + sleep > 3600: # ensure sleep times apply to full hours only
sleep += 3600 % period
# sleep until the next period
time.sleep(sleep)
# run the task, break the loop and exit the scheduler if `False` is returned
if not task():
return
Then you can use use it to run whatever task you want at any full_hour + minute offset. For example:
counter = 0
def your_task():
global counter
counter += 1
if counter > 2:
return False
return True
schedule_hourly_task(your_task, 15)
And it will execute your_task() function every 15 minutes until your_task() returns False - in this case at hh:15, hh:30 and hh:45 before exiting. In your case, calling schedule_hourly_task(your_task, 30) will call the your_task() function every full 30 minutes for as long as your_task() returns True.

python -> time a while loop has been running

i have a loop that runs for up to a few hours at a time. how could I have it tell me how long it has been at a set interval?
just a generic...question
EDIT: it's a while loop that runs permutations, so can i have it print the time running every 10 seconds?
Instead of checking the time on every loop, you can use a Timer object
import time
from threading import Timer
def timeout_handler(timeout=10):
print time.time()
timer = Timer(timeout, timeout_handler)
timer.start()
timeout_handler()
while True:
print "loop"
time.sleep(1)
As noted, this is a little bit of a nasty hack, as it involves checking the time every iteration. In order for it to work, you need to have tasks that run for a small percentage of the timeout - if your loop only iterates every minute, it won't print out every ten seconds. If you want to be interrupted, you might consider multithreading, or preferably if you are on linux/mac/unix, signals. What is your platform?
import time
timeout = 10
first_time = time.time()
last_time = first_time
while(True):
pass #do something here
new_time = time.time()
if new_time - last_time > timeout:
last_time = new_time
print "Its been %f seconds" % (new_time - first_time)
Output:
Its been 10.016000 seconds
Its been 20.031000 seconds
Its been 30.047000 seconds
There's a very hacky way to do this by using time.asctime(). You store the asctime before entering the while loop and somewhere in the loop itself. Calculate the time difference between the stored time and the current time and if that difference is 10 seconds, then update the stored time to the current time and print that it's been running.
However, that's a very hacky way to do it as it requires some twisted and boring math.
If your aim is to check the runtime of a specific algorithm, then you're better off using the timeit module
Hope this Helps

Categories