[英]Scheduling Python Script to run every hour accurately
Before I ask, Cron Jobs and Task Scheduler will be my last options, this script will be used across Windows and Linux and I'd prefer to have a coded out method of doing this than leaving this to the end user to complete.在我问之前, Cron Jobs 和 Task Scheduler将是我最后的选择,这个脚本将在 Windows 和 Linux 上使用,我宁愿有一个编码出来的方法来完成这个而不是留给最终用户来完成。
Is there a library for Python that I can use to schedule tasks?是否有可用于安排任务的 Python 库? I will need to run a function once every hour, however, over time if I run a script once every hour and use.sleep, "once every hour" will run at a different part of the hour from the previous day due to the delay inherent to executing/running the script and/or function.
我将需要每小时运行一次函数,但是,随着时间的推移,如果我每小时运行一次脚本并使用 .sleep,由于延迟,“每小时一次”将在与前一天不同的时间运行执行/运行脚本和/或函数所固有的。
What is the best way to schedule a function to run at a specific time of day (more than once) without using a Cron Job or scheduling it with Task Scheduler?在不使用 Cron Job 或使用 Task Scheduler 安排功能的情况下,安排功能在一天中的特定时间(多次)运行的最佳方法是什么?
Or if this is not possible, I would like your input as well.或者,如果这不可能,我也希望您能提供意见。
import datetime
import time
from apscheduler.scheduler import Scheduler
# Start the scheduler
sched = Scheduler()
sched.daemonic = False
sched.start()
def job_function():
print("Hello World")
print(datetime.datetime.now())
time.sleep(20)
# Schedules job_function to be run once each minute
sched.add_cron_job(job_function, minute='0-59')
out:出去:
>Hello World
>2014-03-28 09:44:00.016.492
>Hello World
>2014-03-28 09:45:00.0.14110
(From Animesh Pandey's answer below) (来自下面的 Animesh Pandey 的回答)
from apscheduler.schedulers.blocking import BlockingScheduler
sched = BlockingScheduler()
@sched.scheduled_job('interval', seconds=10)
def timed_job():
print('This job is run every 10 seconds.')
@sched.scheduled_job('cron', day_of_week='mon-fri', hour=10)
def scheduled_job():
print('This job is run every weekday at 10am.')
sched.configure(options_from_ini_file)
sched.start()
Maybe this can help: Advanced Python Scheduler也许这会有所帮助: Advanced Python Scheduler
Here's a small piece of code from their documentation:这是他们文档中的一小段代码:
from apscheduler.schedulers.blocking import BlockingScheduler
def some_job():
print "Decorated job"
scheduler = BlockingScheduler()
scheduler.add_job(some_job, 'interval', hours=1)
scheduler.start()
To run something every 10 minutes past the hour.每小时每 10 分钟运行一次。
from datetime import datetime, timedelta
while 1:
print 'Run something..'
dt = datetime.now() + timedelta(hours=1)
dt = dt.replace(minute=10)
while datetime.now() < dt:
time.sleep(1)
For apscheduler
< 3.0, see Unknown's answer .对于
apscheduler
< 3.0,请参阅Unknown's answer 。
For apscheduler
> 3.0对于
apscheduler
> 3.0
from apscheduler.schedulers.blocking import BlockingScheduler
sched = BlockingScheduler()
@sched.scheduled_job('interval', seconds=10)
def timed_job():
print('This job is run every 10 seconds.')
@sched.scheduled_job('cron', day_of_week='mon-fri', hour=10)
def scheduled_job():
print('This job is run every weekday at 10am.')
sched.configure(options_from_ini_file)
sched.start()
apscheduler
documentation . apscheduler
文档。
This for apscheduler-3.3.1
on Python 3.6.2
.这适用于
Python 3.6.2
上的apscheduler-3.3.1
。
"""
Following configurations are set for the scheduler:
- a MongoDBJobStore named “mongo”
- an SQLAlchemyJobStore named “default” (using SQLite)
- a ThreadPoolExecutor named “default”, with a worker count of 20
- a ProcessPoolExecutor named “processpool”, with a worker count of 5
- UTC as the scheduler’s timezone
- coalescing turned off for new jobs by default
- a default maximum instance limit of 3 for new jobs
"""
from pytz import utc
from apscheduler.schedulers.blocking import BlockingScheduler
from apscheduler.jobstores.sqlalchemy import SQLAlchemyJobStore
from apscheduler.executors.pool import ProcessPoolExecutor
"""
Method 1:
"""
jobstores = {
'mongo': {'type': 'mongodb'},
'default': SQLAlchemyJobStore(url='sqlite:///jobs.sqlite')
}
executors = {
'default': {'type': 'threadpool', 'max_workers': 20},
'processpool': ProcessPoolExecutor(max_workers=5)
}
job_defaults = {
'coalesce': False,
'max_instances': 3
}
"""
Method 2 (ini format):
"""
gconfig = {
'apscheduler.jobstores.mongo': {
'type': 'mongodb'
},
'apscheduler.jobstores.default': {
'type': 'sqlalchemy',
'url': 'sqlite:///jobs.sqlite'
},
'apscheduler.executors.default': {
'class': 'apscheduler.executors.pool:ThreadPoolExecutor',
'max_workers': '20'
},
'apscheduler.executors.processpool': {
'type': 'processpool',
'max_workers': '5'
},
'apscheduler.job_defaults.coalesce': 'false',
'apscheduler.job_defaults.max_instances': '3',
'apscheduler.timezone': 'UTC',
}
sched_method1 = BlockingScheduler() # uses overrides from Method1
sched_method2 = BlockingScheduler() # uses same overrides from Method2 but in an ini format
@sched_method1.scheduled_job('interval', seconds=10)
def timed_job():
print('This job is run every 10 seconds.')
@sched_method2.scheduled_job('cron', day_of_week='mon-fri', hour=10)
def scheduled_job():
print('This job is run every weekday at 10am.')
sched_method1.configure(jobstores=jobstores, executors=executors, job_defaults=job_defaults, timezone=utc)
sched_method1.start()
sched_method2.configure(gconfig=gconfig)
sched_method2.start()
the simplest option I can suggest is using the schedule library.我可以建议的最简单的选择是使用计划库。
In your question, you said "I will need to run a function once every hour" the code to do this is very simple:在您的问题中,您说“我需要每小时运行一次函数”,执行此操作的代码非常简单:
import schedule
def thing_you_wanna_do():
...
...
return
schedule.every().hour.do(thing_you_wanna_do)
while True:
schedule.run_pending()
you also asked how to do something at a certain time of the day some examples of how to do this are:您还询问了如何在一天中的某个时间做某事,一些示例如下:
import schedule
def thing_you_wanna_do():
...
...
return
schedule.every().day.at("10:30").do(thing_you_wanna_do)
schedule.every().monday.do(thing_you_wanna_do)
schedule.every().wednesday.at("13:15").do(thing_you_wanna_do)
# If you would like some randomness / variation you could also do something like this
schedule.every(1).to(2).hours.do(thing_you_wanna_do)
while True:
schedule.run_pending()
90% of the code used is the example code of the schedule library.使用的代码90%是调度库的示例代码。 Happy scheduling!
安排愉快!
#For scheduling task execution
import schedule
import time
def job():
print("I'm working...")
schedule.every(1).minutes.do(job)
#schedule.every().hour.do(job)
#schedule.every().day.at("10:30").do(job)
#schedule.every(5).to(10).minutes.do(job)
#schedule.every().monday.do(job)
#schedule.every().wednesday.at("13:15").do(job)
#schedule.every().minute.at(":17").do(job)
while True:
schedule.run_pending()
time.sleep(1)
Run the script every 15 minutes of the hour.每小时每 15 分钟运行一次脚本。 For example, you want to receive 15 minute stock price quotes, which are updated every 15 minutes.
例如,您希望接收 15 分钟的股票报价,每 15 分钟更新一次。
while True:
print("Update data:", datetime.now())
sleep = 15 - datetime.now().minute % 15
if sleep == 15:
run_strategy()
time.sleep(sleep * 60)
else:
time.sleep(sleep * 60)
On the version posted by sunshinekitty called "Version < 3.0" , you may need to specify apscheduler 2.1.2 .在 sunkitty 发布的名为 "Version < 3.0" 的版本上,您可能需要指定 apscheduler 2.1.2 。 I accidentally had version 3 on my 2.7 install, so I went:
我不小心在我的 2.7 安装中安装了版本 3,所以我去了:
pip uninstall apscheduler
pip install apscheduler==2.1.2
It worked correctly after that.之后它工作正常。 Hope that helps.
希望有帮助。
The Python standard library does provide sched andthreading for this task. Python 标准库确实为此任务提供了调度和线程。 But this means your scheduler script will have be running all the time instead of leaving its execution to the OS, which may or may not be what you want.
但这意味着您的调度程序脚本将一直运行,而不是将其执行留给操作系统,这可能是您想要的,也可能不是您想要的。
Probably you got the solution already @lukik, but if you wanna remove a scheduling, you should use:可能你已经得到了@lukik 的解决方案,但是如果你想删除一个调度,你应该使用:
job = scheduler.add_job(myfunc, 'interval', minutes=2)
job.remove()
or或者
scheduler.add_job(myfunc, 'interval', minutes=2, id='my_job_id')
scheduler.remove_job('my_job_id')
if you need to use a explicit job ID如果您需要使用明确的作业 ID
For more information, you should check: https://apscheduler.readthedocs.io/en/stable/userguide.html#removing-jobs有关更多信息,您应该查看: https ://apscheduler.readthedocs.io/en/stable/userguide.html#removing-jobs
I found that scheduler needs to run the program every second.我发现调度程序需要每秒运行一次程序。 If using a online server it would be costly.
如果使用在线服务器,成本会很高。 So I have following:
所以我有以下几点:
It run at each minute at the 5th second, and you can change it to hours days by recalculating waiting period in seconds它在第 5 秒的每分钟运行一次,您可以通过重新计算等待时间(以秒为单位)将其更改为小时天
import time
import datetime
Initiating = True
print(datetime.datetime.now())
while True:
if Initiating == True:
print("Initiate")
print( datetime.datetime.now())
time.sleep(60 - time.time() % 60+5)
Initiating = False
else:
time.sleep(60)
print("working")
print(datetime.datetime.now())
This method worked for me using relativedelta and datetime and a modulo boolean check for every hour.这种方法对我有用,它使用 relativedelta 和 datetime 以及每小时的模布尔检查。 It runs every hour from the time you start it.
从您启动它开始,它每小时运行一次。
import time
from datetime import datetime, timedelta
from dateutil.relativedelta import relativedelta
#Track next run outside loop and update the next run time within the loop
nxt_run=datetime.now()
#because while loops evaluate at microseconds we basically need to use a boolean evaluation to track when it should run next
while True:
cnow = datetime.now() #track the current time
time.sleep(1) #good to have so cpu doesn't spike
if (cnow.hour % 1 == 0 and cnow >= nxt_run):
print(f"start @{cnow}: next run @{nxt_run}")
nxt_run=cnow+relativedelta(hours=1) #add an hour to the next run
else:
print(f"next run @{nxt_run}")
clock.py时钟.py
from apscheduler.schedulers.blocking import BlockingScheduler
import pytz
sched = BlockingScheduler(timezone=pytz.timezone('Africa/Lagos'))
@sched.scheduled_job('cron', day_of_week='mon-sun', hour=22)
def scheduled_job():
print('This job is run every week at 10pm.')
#your job here
sched.start()
Procfile档案
clock: python clock.py
requirements.txt要求.txt
APScheduler==3.0.0
After deployment, the final step is to scale up the clock process.部署后,最后一步是扩展时钟进程。 This is a singleton process, meaning you'll never need to scale up more than 1 of these processes.
这是一个单例流程,这意味着您永远不需要扩大超过 1 个这些流程。 If you run two, the work will be duplicated.
如果你运行两个,工作将被重复。
$ heroku ps:scale clock=1
Source: https://devcenter.heroku.com/articles/clock-processes-python来源: https ://devcenter.heroku.com/articles/clock-processes-python
Perhaps Rocketry suits your needs.也许Rocketry适合您的需求。 It's a powerful scheduler that is very easy to use, has a lot of built-in scheduling options and it is easy to extend:
它是一个功能强大的调度器,非常易于使用,具有很多内置的调度选项,并且易于扩展:
from rocketry import Rocketry
from rocketry.conds import daily, every, after_success
app = Rocketry()
@app.task(every("1 hour 30 minutes"))
def do_things():
...
@app.task(daily.between("12:00", "17:00"))
def do_daily_afternoon():
...
@app.task(daily & after_success(do_things))
def do_daily_after_task():
...
if __name__ == "__main__":
app.run()
It has much more though:它还有更多:
Links:链接:
Disclaimer: I'm the author免责声明:我是作者
One option is to write a C/C++ wrapper that executes the python script on a regular basis.一种选择是编写一个定期执行 python 脚本的 C/C++ 包装器。 Your end-user would run the C/C++ executable, which would remain running in the background, and periodically execute the python script.
您的最终用户将运行 C/C++ 可执行文件,该可执行文件将继续在后台运行,并定期执行 python 脚本。 This may not be the best solution, and may not work if you don't know C/C++ or want to keep this 100% python.
这可能不是最好的解决方案,如果您不了解 C/C++ 或想保留这个 100% python,则可能无法正常工作。 But it does seem like the most user-friendly approach, since people are used to clicking on executables.
但这似乎是最用户友好的方法,因为人们习惯于单击可执行文件。 All of this assumes that python is installed on your end user's computer.
所有这些都假设 python 安装在您的最终用户的计算机上。
Another option is to use cron job/Task Scheduler but to put it in the installer as a script so your end user doesn't have to do it.另一种选择是使用 cron 作业/任务计划程序,但将其作为脚本放入安装程序中,这样您的最终用户就不必这样做了。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.