How to schedule different tasks at different times in never-ending program - python

I'll preface this by saying I'm not an advanced programmer and I have only written programs that run sequentially and exit. What I'd like to do now is write a python script that I'll launch and it will run a function every 5 minutes and another function every 10 minutes and do so indefinitely. Here's some pseudo-code:
def RunMeEvery5min:
do something
def RunMeEvery10min:
do something
while True:
every 5 minutes run RunMeEvery5min
every 10 minutes run RunMeEvery10min
do this forever until I kill the program
So is this threading? It really doesn't matter if the tasks line up or not as they're essentially unrelated. I would venture to guess that this is a common type of programming question, but I've never really understood how to accomplish this and I don't even know what to search for. Any helpful examples or links to basic tutorials would be much appreciated!
Thanks!

Maybe this will help you https://github.com/dbader/schedule
import schedule
import time
def job():
print("I'm working...")
schedule.every(10).minutes.do(job)
while True:
schedule.run_pending()
time.sleep(1)

You can use sched from Python standard library.
import sched, time
from datetime import datetime
scheduler = sched.scheduler(time.time, time.sleep)
def execute_every_05mins():
print(datetime.now().strftime("%H:%M:%S"))
scheduler.enter(300, 0, execute_every_05mins, ())
def execute_every_10mins():
print(datetime.now().strftime("%H:%M:%S"))
scheduler.enter(600, 0, execute_every_10mins, ())
if __name__ == "__main__":
scheduler.enter(0, 0, execute_every_05mins, ())
scheduler.enter(0, 0, execute_every_10mins, ())
scheduler.run()

Related

Repeat python function at every system clock minute

I've seen that I can repeat a function with python every x seconds by using a event loop library in this post:
import sched, time
s = sched.scheduler(time.time, time.sleep)
def do_something(sc):
print("Doing stuff...")
# do your stuff
s.enter(60, 1, do_something, (sc,))
s.enter(60, 1, do_something, (s,))
s.run()
But I need something slightly different: I need that the function will be called at every system clock minute: at 11:44:00PM, 11:45:00PM and so on.
How can I achieve this result?
Use schedule.
import schedule
import time
schedule.every().minute.at(':00').do(do_something, sc)
while True:
schedule.run_pending()
time.sleep(.1)
If do_something takes more than a minute, threadidize it before passing it to do.
import threading
def do_something_threaded(sc):
threading.Thread(target=do_something, args=(sc,)).start()
Exactly 0 is very hard to accomplish (since there is always a small delay) but You can check if the minute has changed:
import datetime
minute = None
while True:
if datetime.datetime.now().minute != minute:
print(f'Do something {datetime.datetime.now()}')
minute = datetime.datetime.now().minute
result at my mahcine:
Do something 2022-01-21 11:24:39.393919
Do something 2022-01-21 11:25:00.000208
So it checks if there is a new minute and calls again the datetime function. The delay is around 0.2 milliseconds.
If you think along the lines of a forever running program, you have to ping the system time using something like now = datetime.now(). Now if you want 1 sec accuracy to catch that :00 window, that means you have to ping a lot more often.
Usually a better way is to schedule the script execution outside using Windows Task Scheduler or Crontab in Linux systems.
For example, this should run every XX:YY:00:
* * * * * python run_script.py

schedule a python script to run every hour

I am trying to write a script that executes every hour
but, when I run it... it takes an hour to run the job for the first time and then, it starts running like every 5 seconds
I don't understand what am I doing wrong here
from apscheduler.schedulers.blocking import BlockingScheduler
def job():
print('excuting job')
scheduler = BlockingScheduler()
scheduler.add_job(job, 'interval', hours = 1)
scheduler.start()
this is another code that I have used, but it's the same result
schedule.every().hour.do(job)
while True:
schedule.run_pending()
time.sleep(20)
Don't do it in python.
Make a file called exehour.bat with this (assuming you're using Windows):
#echo off
cd DIRECTORY-OF-FILE
:loop
timeout 3600
FILE-NAME
goto loop
So this will execute a file every 1 hour when you run it
Or if you need it in python
import time
def runhour():
#YOUR PYTHON CODE GOES UNDERNEATH HERE
#
time.sleep(3600)
Might have something to do within your def, like a rogue brake or other bad while loop or sleep timer. Maybe the checking job timer not being short enough is affecting something as well?
import schedule # I'm not sure about the BlockingScheduler import but this one works for me
import time # Hate how we need an import for this and it's not built into python....
def job():
print('executing job')
# Run your job on first boot without the scheduler
job()
# Then setup the schedule to be used from now on
schedule.every().hour.do(job)
# Check every second if we can do our job yet or not
# Bonus heartbeat . so you know the while loop is running and not crashed.
while True:
schedule.run_pending()
print(".", end="", flush=True)
time.sleep(1) # seconds
If it runs our job() then gets stuck, boot loops or crashes then its in your job def.
if it runs fine the first time, sets up the schedule fine but then gets stuck with executing the schedule then I don't really have any ideas without seeing more of the job() def..
for shits and giggles you could pip uninstall and reinstall schedule again and see if that helps idk..

Executing a function after a certain period of time

I am building a discord bot with discordpy and I want a function to be executed every ten minutes (for a mini game) but if I use time.sleep the entire program will freeze and wait for that time, rendering my bot completely useless because of the fact that time.sleep stops the program from executing. Also discordpy works with async functions and events so trying to find a place to put a while loop is very difficult. Is there a module that I can use to execute a function every ten minutes without stopping the flow of my bot?
edit:
with discordpy, you define all of your async functions so:
#client.event
async def on_message(message):
# Code
And than at the end of the file you write:
client.run()
What I am saying is, I cant use an infinite while loop because of the fact that I need to reach that line, without that line the bot will be useless, So what my question is, can I "attach" a timer to my script so that every ten minutes I can execute a function?
you use scheduling for this
import sched, time
sch = sched.scheduler(time.time, time.sleep)
def run_sch(do):
print("running at 10 mins")
# do your stuff
sch.enter(600, 1, run_sch, (do,))
sch.enter(600, 1, run_sch, (s,))
sch.run()
or you can try threading for running that specific function for every 10 mins
import threading
def hello_world():
while True:
print("Hello, World!")
time.sleep(600)
t1 = threading.Thread(target=hello_world)
t1.start()
while True:
print('in loop')
time.sleep(1)
Tell me what you think about this. If it does not work with your code then I can adjust it:
import time
starttime=time.time()
def thing():
print('hi')
while True:
thing()
time.sleep(60.0 - ((time.time() - starttime) % 60.0))
It's in a while loop so I don't know how well that will work with your code but since it is a bot that runs multiple times, it might work. Of course if you want it to run only 5 times for example you can just say for i in range(5):
Hope this helps!
Try something like this,
import schedule
def worker():
print("Executing...")
schedule.every(10).minutes.do(worker)
while True:
schedule.run_pending()
time.sleep(1)
Also, there are different packages we can use to achieve this feature.
import sched
sched.scheduler(params)
Threading along with sleep.
Use of Twisted package etc..
Discord.py is build with python asyncio module. To sleep the current task in asyncio, you need to await on asyncio.sleep() Note that this will not block your thread or the event loop and is exactly what you should use.
import asyncio #Top of your file
...
await asyncio.sleep(10) #Doesn't blocks the rest of the program!
Creating a thread as mentioned in the answer by NAGA RAJ S is not recommended in asynchronous programs and is a waste of resource.
More about asyncio.sleep v/s time.sleep: Python 3.7 - asyncio.sleep() and time.sleep()

5 minutes loop in python does it causing issue?

I am using this loop for running every 5 minutes just creating thread and it completes.
while True:
now_plus_5 = now + datetime.timedelta(minutes = 5)
while datetime.datetime.now()<= now_plus_5:
new=datetime.datetime.now()
pass
now = new
pass
But when i check my process status it shows 100% usage when the script runs.Does it causing problem?? or any good ways??
Does it causes CPU 100% usage??
You might rather use something like time.sleep
while True:
# do something
time.sleep(5*60) # wait 5 minutes
Based on your comment above, you may find a Timer object from the threading module to better suit your needs:
from threading import Timer
def hello():
print "hello, world"
t = Timer(300.0, hello)
t.start() # after 5 minutes, "hello, world" will be printed
(code snippet modified from docs)
A Timer is a thread subclass, so you can further encapsulate your logic as needed.
This allows the threading subsystem to schedule the execution of your task such that it's not entirely CPU bound like your current implementation.
I should also note that the Timer class is designed to be fired only once. As such, you'd want to design your task to start a new instance upon completion, or create your own Thread subclass with its own smarts.
While researching this, I noticed that there's also a sched module that provides this functionality as well, but rather than rehash the solution, check out this related question:
Python Equivalent of setInterval()?
timedelta takes(seconds,minutes,hours,days,months,years) as input and works accordingly
from datetime import datetime,timedelta
end_time = datetime.now()+timedelta(minutes=5)
while end_time>= datetime.now():
statements

Trigger a Python function exactly on the minute

I have a function that I want to trigger at every turn of the minute — at 00 seconds. It fires off a packet over the air to a dumb display that will be mounted on the wall.
I know I can brute force it with a while loop but that seems a bit harsh.
I have tried using sched but that ends up adding a second every minute.
What are my options?
You might try APScheduler, a cron-style scheduler module for Python.
From their examples:
from apscheduler.scheduler import Scheduler
# Start the scheduler
sched = Scheduler()
sched.start()
def job_function():
print "Hello World"
sched.add_cron_job(job_function, second=0)
will run job_function every minute.
What if you measured how long it took your code to execute, and subtracted that from a sleep time of 60?
import time
while True:
timeBegin = time.time()
CODE(.....)
timeEnd = time.time()
timeElapsed = timeEnd - timeBegin
time.sleep(60-timeElapsed)
The simplest solution would be to register a timeout with the operating system to expire when you want it to.
Now there are quite a few ways to do so with a blocking instruction and the best option depends on your implementation. Simplest way would be to use time.sleep():
import time
current_time = time.time()
time_to_sleep = 60 - (current_time % 60)
time.sleep(time_to_sleep)
This way you take the current time and calculate the amount of time you need to sleep (in seconds). Not millisecond accurate but close enough.
APScheduler is the correct approach. The syntax has changed since the original answer, however.
As of APScheduler 3.3.1:
def fn():
print("Hello, world")
from apscheduler.schedulers.background import BackgroundScheduler
scheduler = BackgroundScheduler()
scheduler.start()
scheduler.add_job(fn, trigger='cron', second=0)
You can try Threading.Timer
See this Example
from threading import Timer
def job_function():
Timer(60, job_function).start ()
print("Running job_funtion")
It will print "Running job_function" every Minute
Edit:
If we are critical about the time at which it should run
from threading import Timer
from time import time
def job_function():
Timer(int(time()/60)*60+60 - time(), job_function).start ()
print("Running job_funtion")
It will run exactly at 0th second of every minute.
The syntax has been changed, so in APScheduler of version 3.6.3 (Released: Nov 5, 2019) use the following snippet:
from apscheduler.schedulers.blocking import BlockingScheduler
from apscheduler.triggers.cron import CronTrigger
def fn():
print('Hello, world!')
sched = BlockingScheduler()
# Execute fn() at the start of each minute.
sched.add_job(fn, trigger=CronTrigger(second=00))
sched.start()
The Python time module is usually what I use for events like this. It has a method called sleep(t), where t equals the time in seconds you want to delay.
Combined with a while loop, you can get what you're looking for:
import time
while condition:
time.sleep(60)
f(x)
May use this example:
def do():
print("do do bi do")
while True:
alert_minutes= [15,30,45,0]
now=time.localtime(time.time())
if now.tm_min in alert_minutes:
do()
time.sleep(60)
you could use a while loop and sleep to not eat up the processor too much

Categories