python asyncio和celery_Python定时任务-schedule vs. Celery vs. APScheduler

在Python开发过程中我们经常需要执行定时任务,而此类任务我们通常有如下选项:

自己造轮子

使用schedule库

使用Celery定时任务

使用APScheduler

自己造轮子实现,最大的优势就是灵活性,调试方便,对于某些特定系统也许也是一种选择,不过对于大多数应用来说,我们应当尽可能地使用开源的成熟的方案。下面对后三种方案分别讨论:

使用schedule库

schedule库是一个轻量级的定时任务方案,优势是使用简单,也不需要做什么配置;缺点是无法动态添加任务,也无法将任务持久化。

安装

pip install schedule

使用

import schedule

import time

def job():

print("I'm working...")

schedule.every(10).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)

while True:

schedule.run_pending()

time.sleep(1)

使用Celery

Celery在Python领域可谓大名鼎鼎,我们通常将Celery作为一个任务队列来使用,不过Celery也同时提供了定时任务功能。通常,当我们的解决方案中已经在使用Celery的时候可以考虑同时使用其定时任务功能,但是Celery无法在Flask这样的系统中动态添加定时任务(在Django中有相应的插件可以实现动态添加任务),而且如果对于不使用Celery的项目,单独为定时任务搭建Celery显得过于重量级了。(搭建Celery比较麻烦,还需要配置诸如RabbitMQ之类消息分发程序)。

Celery安装在此不再赘述,大家可以参考官网的资料

使用

Celery虽然无法动态添加定时任务,但是可以在程序固定位置添加定时任务,如下:

from celery import Celery

from celery.schedules import crontab

app = Celery()

# 此处on_after_configure装饰符意味着当Celery app配置完成之后调用该hook函数

@app.on_after_configure.connect

def setup_periodic_tasks(sender, **kwargs):

# Calls test('hello') every 10 seconds.

sender.add_periodic_task(10.0, test.s('hello'), name='add every 10')

# Calls test('world') every 30 seconds

sender.add_periodic_task(30.0, test.s('world'), expires=10)

# Executes every Monday morning at 7:30 a.m.

sender.add_periodic_task(

crontab(hour=7, minute=30, day_of_week=1),

test.s('Happy Mondays!'),

)

@app.task

def test(arg):

print(arg)

这里调用add_periodic_task用于添加一个定时任务,相当于在Celery config文件中的beat_schedule设置项中添加了一项,如下:

app.conf.beat_schedule = {

'add-every-30-seconds': {

'task': 'tasks.add',

'schedule': 30.0,

'args': (16, 16)

},

}

在add_periodic_task中指定job function时需要用.s()来调用

使用APScheduler

笔者认为APScheduler是在实际项目最好用的一个工具库。它不仅可以让我们在程序中动态添加和删除我们的定时任务,还支持持久化,且其持久化方案支持很多形式,包括(Memory, MongoDB, SQLAlchemy, Redis, RethinkDB, ZooKeeper), 也可以非常好与一些Python framework集成(包括asyncio, gevent, Tornado, Twisted, Qt). 笔者所在的项目使用的是Flask框架,也有相应的插件可以供我们直接使用。

但是笔者没有使用插件,而是直接将APScheduler集成于项目代码中。

初始化scheduler

# 可以在初始化Flask的时候调用,并将返回的scheduler赋给app

def init_scheduler():

# 这里用于持久化的设置,代码中演示使用MongoDB

# client用于设置你自己的MongoDB的handler, 即MongoClient对象

jobstores = {

'default': MongoDBJobStore(client=your_db_handler, collection="schedule_job")

}

executors = {

'default': ThreadPoolExecutor(20)

}

job_defaults = {

'coalesce': False,

'max_instances': 5

}

# 这里使用BackgroundScheduler即可

scheduler = BackgroundScheduler(jobstores=jobstores, executors=executors, job_defaults=job_defaults, timezone=utc)

# 注意这里一定要调用start启动scheduler

scheduler.start()

return scheduler

添加定时任务

APScheduler将定时任务分为三种:

interval: 比如每隔5分钟执行一次任务

cron: 比如每天早上5点执行一次任务

date: 比如在2018年5月5日执行一次任务

我们以添加cron job为例:

def test_job(name):

print "hello, %s" % name

def add_daily_job(name):

exec_time = datetime.now() + timedelta(minutes=2)

hour = exec_time.strftime("%H")

minute = exec_time.strftime("%M")

# 这里要选择'cron'

# 另外,job_id可以根据你自己的情况设定,其会被用于remove_job

current_app.scheduler.add_job(

test_job, 'cron', hour=hour, minute=minute,

args=[name], id=job_id)

删除定时任务

通过在add_job时使用的job_id可以删除对应的定时任务。实际上在我们添加任务的时候,APScheduler会把相应的任务信息存储于我们jobstore中设置的持久化存储方案,这里使用的是MongoDB,然后当删除的时候会将相应的任务从MongoDB中删除。

def remove_daily_job(job_id):

current_app.scheduler.remove_job(job_id)

总结:

APScheduler在实际使用过程中拥有最大的灵活性,可以满足我们的大部分定时任务的相关需求;Celery比较重量级,通常如果项目中已有Celery在使用,而且不需要动态添加定时任务时可以考虑使用;schedule非常轻量级,使用简单,但是不支持任务的持久化,也无法动态添加删除任务,所以主要用于简单的小型应用。

References

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要实现可前端添加定时任务,可以使用 Django 的 celery_beat 库和 MySQL 数据库。 首先,需要安装 celerycelery_beat 库: ``` pip install celery django-celery-beat ``` 然后,在 Django 的 settings.py 文件中设置 celerycelery_beat 的相关配置: ```python # 配置 celery CELERY_BROKER_URL = 'redis://localhost:6379/0' CELERY_RESULT_BACKEND = 'redis://localhost:6379/0' # 配置 celery_beat CELERY_BEAT_SCHEDULER = 'django_celery_beat.schedulers:DatabaseScheduler' ``` 接下来,创建一个 app,用于存储定时任务的配置信息。这里假设 app 名称为 `tasks`,在 models.py 中定义一个 `Task` 模型: ```python from django.db import models class Task(models.Model): name = models.CharField(max_length=256) task = models.CharField(max_length=256) args = models.TextField(default='[]') kwargs = models.TextField(default='{}') schedule = models.CharField(max_length=256) ``` 这个模型包含了任务的名称、任务函数、参数、关键字参数和调度器配置信息。 接下来,需要在 app 的 admin.py 文件中注册 `Task` 模型,并自定义 admin 页面的表单。这里使用 `JSONEditorWidget` 来渲染参数和关键字参数的输入框: ```python from django.contrib import admin from django_json_widget.widgets import JSONEditorWidget from .models import Task @admin.register(Task) class TaskAdmin(admin.ModelAdmin): formfield_overrides = { models.TextField: {'widget': JSONEditorWidget}, } ``` 现在,可以在 admin 页面中添加、删除、修改定时任务的配置信息了。但是,这些配置信息并没有被 celery_beat 调度器使用。为了让 celery_beat 调度器能够使用这些信息,需要在 app 的 `apps.py` 文件中注册定时任务: ```python from django.apps import AppConfig from django.conf import settings from celery import Celery from celery.schedules import crontab from .models import Task class TasksConfig(AppConfig): name = 'tasks' def ready(self): # 创建 celery 实例 app = Celery('tasks', broker=settings.CELERY_BROKER_URL) # 获取所有定时任务配置信息 tasks = Task.objects.all() # 注册定时任务 for task in tasks: app.conf.beat_schedule[task.name] = { 'task': task.task, 'schedule': crontab(task.schedule), 'args': eval(task.args), 'kwargs': eval(task.kwargs), } ``` 这里通过 `AppConfig.ready()` 方法,在 app 启动时注册定时任务。在注册任务时,需要将 `args` 和 `kwargs` 字段的字符串转换成 Python 对象。最后,需要在项目的 __init__.py 文件中配置 app 的默认 AppConfig: ```python default_app_config = 'tasks.apps.TasksConfig' ``` 现在,就可以启动 celerycelery_beat 服务了: ``` celery -A proj worker -l info celery -A proj beat -l info ``` 启动服务后,即可根据 admin 页面上的定时任务配置信息自动调度任务了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值