Install the apscheduler module
pip install apscheduler pip install django-apscheduler
Add django-apscheduler to INSTALLED_APPS in the settings of the project
INSTALLED_APPS = [ .... 'django_apscheduler', ]
carried out:
# python manage.py migrate no other table structure do not have to run python manage.py makemigrations
Two tables will be created: django_apscheduler_djangojob / django_apscheduler_djangojobexecution
can easily manage scheduled tasks by entering the background management.
In the urls.py file in the Django project directory, or the main urls.py, introduce the following content
from apscheduler.schedulers.background import BackgroundScheduler from django_apscheduler.jobstores import DjangoJobStore, register_events, register_job scheduler = BackgroundScheduler() scheduler.add_jobstore(DjangoJobStore(), "default") # 时间间隔3秒钟打印一次当前的时间 @register_job(scheduler, "interval", seconds=3, id='test_job') def test_job(): print("我是apscheduler任务") # per-execution monitoring, call register_events on your scheduler register_events(scheduler) scheduler.start() print("Scheduler started!")
The results are as follows:
The difference between the two schedulers in APScheduler and the problems to be paid attention to during use
There are many different types of schedulers in APScheduler, BlockingScheduler and BackgroundScheduler are the two most commonly used schedulers. The main difference is that BlockingScheduler will block the main thread, while BackgroundScheduler will not block. Therefore, we choose different schedulers in different situations:
BlockingScheduler
: Calling the start function will block the current thread. Used when the scheduler is the only thing in your application that you want to run (as in the example above).BackgroundScheduler
: The main thread will not block after calling start. Use when you are not running any other framework and want the scheduler to execute in the background of your application.
A real example of BlockingScheduler
from apscheduler.schedulers.blocking import BlockingScheduler import time def job(): print('job 3s') if __name__=='__main__': sched = BlockingScheduler(timezone='MST') sched.add_job(job, 'interval', id='3_second_job', seconds=3) sched.start() while(True): print('main 1s') time.sleep(1) 运行结果: job 3s job 3s job 3s job 3s
It can be seen that BlockingScheduler
calling the start function will block the current thread, resulting in the while loop in the main program will not be executed.
BackgroundScheduler
Real example
from apscheduler.schedulers.background import BackgroundScheduler import time def job(): print('job 3s') if __name__=='__main__': sched = BackgroundScheduler(timezone='MST') sched.add_job(job, 'interval', id='3_second_job', seconds=3) sched.start() while(True): print('main 1s') time.sleep(1) 运行结果: main 1s main 1s main 1s job 3s main 1s main 1s main 1s job 3s
It can be seen that the BackgroundScheduler
current thread is not blocked after calling the start function, so the logic of the while loop in the main program can be continued.
Through this output, we can also find that after calling the start function, job () does not start execution immediately. Instead, it will be scheduled for execution after waiting for 3s.
How to make the job start running after start ()
How can the job () be executed immediately after the scheduler calls the start function?
In fact, APScheduler
there is no good way to solve this problem, but there is one of the simplest way is to run a job () before the scheduler start, as follows
from apscheduler.schedulers.background import BackgroundScheduler import time def job(): print('job 3s') if __name__=='__main__': job() sched = BackgroundScheduler(timezone='MST') sched.add_job(job, 'interval', id='3_second_job', seconds=3) sched.start() while(True): print('main 1s') time.sleep(1) 运行结果: job 3s main 1s main 1s main 1s job 3s main 1s main 1s main 1s
In this way, although it is not absolutely possible to "let the job start after start ()", it can also be "not waiting for the schedule, but running the job at the beginning".
What if the job execution time is too long
If the execution time of job () takes 5s, but the scheduler is configured to call job () every 3s, what will happen? We wrote the following example:
from apscheduler.schedulers.background import BackgroundScheduler import time def job(): print('job 3s') time.sleep(5) if __name__=='__main__': sched = BackgroundScheduler(timezone='MST') sched.add_job(job, 'interval', id='3_second_job', seconds=3) sched.start() while(True): print('main 1s') time.sleep(1) 运行结果: main 1s main 1s main 1s job 3s main 1s main 1s main 1s Execution of job "job (trigger: interval[0:00:03], next run at: 2018-05-07 02:44:29 MST)" skipped: maximum number of running instances reached (1) main 1s main 1s main 1s job 3s main 1s
It can be seen that after the 3s time arrives, it will not "restart a job thread", but will skip the scheduling, wait for the next cycle (waiting for another 3s), and reschedule the job ().
In order to allow multiple jobs () to run at the same time, we can also configure the parameters of the scheduler max_instances
, as in the following example, we allow 2 jobs () to run at the same time
from apscheduler.schedulers.background import BackgroundScheduler import time def job(): print('job 3s') time.sleep(5) if __name__=='__main__': job_defaults = { 'max_instances': 2 } sched = BackgroundScheduler(timezone='MST', job_defaults=job_defaults) sched.add_job(job, 'interval', id='3_second_job', seconds=3) sched.start() while(True): print('main 1s') time.The result of sleep (1) job 3s main 1s main 1s main 1s job 3s main 1s main 1s main 1s job 3s main 1s main 1s main 1s operation:
How each job is scheduled
Through the above example, we found that the scheduler schedules the job () function regularly to achieve scheduling.
Will the job () function be scheduled to run as a process, or will it run as a thread?
In order to clarify this problem, we wrote the following program:
from apscheduler.schedulers.background import BackgroundScheduler import time,os,threading def job(): print('job thread_id-{0}, process_id-{1}'.format(threading.get_ident(), os.getpid())) time.sleep(50) if __name__=='__main__': job_defaults = { 'max_instances': 20 } sched = BackgroundScheduler(timezone='MST', job_defaults=job_defaults) sched.add_job(job, 'interval', id='3_second_job', seconds=3) sched.start() while(True): print('main 1s') time.sleep(1) 运行结果: main 1s main 1s main 1s job thread_id-10644, process_id-8872 main 1s main 1s main 1s job thread_id-3024, process_id-8872 main 1s main 1s main 1s job thread_id-6728, process_id-8872 main 1s main 1s main 1s job thread_id-11716, process_id-8872
It can be seen that the process ID of each job () is the same, but the thread ID is different. Therefore, job () is ultimately scheduled for execution in the form of threads.
Summary of ways to trigger tasks:
date
from datetime import date from apscheduler.schedulers.blocking import BlockingScheduler sched = BlockingScheduler() def my_job(text): print(text) # 在2030年04月21日执行 sched.add_job(my_job, 'date', run_date=date(2020, 04, 21), args=['text']) sched.start()
The run_date
parameters can be date type, datetime type or text type.
datetime type (for precise time)
# Execute sched.add_job (my_job, 'date', run_date = datetime (2009, 11, 6, 16, 30, 5), args = ['text']) at 16:30:05 on November 6, 2009