Celery使用:优秀的python异步任务框架
目录
- Celery 简介
- 介绍
- 安装
- 基本使用
- Flask使用Celery
- 异步任务
- 定时任务
- Celery使用Flask上下文
- 进阶使用参考
- 停止Worker
- 后台运行
Celery 简介
介绍
Celery 是一个简单、灵活且可靠的,处理大量消息的分布式系统,并且提供维护这样一个系统的必需工具。
它是一个专注于实时处理的任务队列,同时也支持任务调度。
Celery 通过消息机制进行通信,通常需要中间人(Broker)和工作者(Worker)来进行调节。其中Broker就是消息中间件(常用的rabbitmq和redis),主要用来进行发送和接收消息;Worker就是任务的执行单元,通常是开发者来自己定义任务的内容。
Celery 特点:
- 简单:Celery 上手比较简单,不需要配置文件就可以直接运行;
- 高可用:如果出现丢失连接或连接失败,职程(Worker)和客户端会自动重试,并且中间人通过 主/主 主/从 的方式来进行提高可用性;
- 快速:单个 Celery 进行每分钟可以处理数以百万的任务,而且延迟仅为亚毫秒(使用 RabbitMQ、 librabbitmq 在优化过后);
- 灵活:Celery 的每个部分几乎都可以自定义扩展和单独使用,例如自定义连接池、序列化方式、压缩方式、日志记录方式、任务调度、生产者、消费者、中间人(Broker)等。
Celery 主要用途:
- 异步执行:解决耗时任务,将耗时操作任务提交给Celery去异步执行,比如发送短信/邮件、消息推送、音视频处理等等;
- 延迟执行:解决延迟任务,比如有些跑批接口的任务,需要耗时比较长;
- 调度:可以通过调度功能在一段时间内指定任务的执行时间 datetime,也可以根据简单每隔一段时间进行执行重复的任务,支持分钟、小时、星期几,也支持某一天或某一年的Crontab表达式。
Celery 主要架构:
celery 的5个主要角色:
- Task:就是任务,有异步任务和定时任务;
- Broker:中间人,接收生产者发来的消息即Task,将任务存入队列。任务的消费者是Worker。Celery本身不提供队列服务,推荐用Redis或RabbitMQ实现队列服务;
- Worker:执行任务的单元,它实时监控消息队列,如果有任务就获取任务并执行它;
- Beat:定时任务调度器,根据配置定时将任务发送给Broker;
- Backend:用于存储任务的执行结果(例如:SQLAlchemy/Django] ORM、Memcached、Redis、 RPC RabbitMQ/AMQP)以及自定义的后端结果存储中间件)。
安装
安装比较简单,命令如下:
pip install Celery
另外Celery 自定义了一组用于安装 Celery 和特定功能的依赖。可以在中括号加入您需要依赖,并可以通过逗号分割需要安装的多个依赖包,例如安装rabbitmq和redis依赖,如下:
pip install "celery[librabbitmq,redis]"
注意:RabbitMQ 是默认的中间人(Broker),只需要配置连接的URL即可,不需要安装额外的的配置以及初始化配置信息。但是使用redis作为中间件时(或作为结果存储),必须要安装 Celery 的依赖库,按照上面的命令即可。
基本使用
选用rabbitmq
作为Broker。
创建一个工程,保存为一个 app 文件中。针对大型的项目,可能需要创建 独立的模块。
首先创建 tasks.py:
from celery import Celeryapp = Celery('tasks',broker='amqp://guest:guest@localhost:5672',backend='redis://localhost')@app.task
def add(x, y):return x + y
Celery
参数:
第一个参数为当前模块的名称,只有在 __main__
模块中定义任务时才会生产名称。
第二个参数为中间人(Broker)的链接 URL ,实例中使用的 RabbitMQ(Celery默认使用的也是RabbitMQ)。
第三个参数为后端结果链接,实例中使用的redis。
这里创建了一个名称为 add 的任务,返回的俩个数字的和。
然后启动celery服务:
celery -A tasks worker --loglevel=info
成功运行后,打印如下信息:
-------------- celery@testdeMacBook-Pro.local v5.2.7 (dawn-chorus)
--- ***** -----
-- ******* ---- macOS-10.16-x86_64-i386-64bit 2023-01-03 21:39:48
- *** --- * ---
- ** ---------- [config]
- ** ---------- .> app: tasks:0x7fcbf8ce4e20
- ** ---------- .> transport: amqp://guest:**@localhost:5672//
- ** ---------- .> results: redis://localhost/
- *** --- * --- .> concurrency: 8 (prefork)
-- ******* ---- .> task events: OFF (enable -E to monitor tasks in this worker)
--- ***** ----- -------------- [queues].> celery exchange=celery(direct) key=celery[tasks]. tasks.add[2023-01-03 21:39:48,906: INFO/MainProcess] Connected to amqp://guest:**@127.0.0.1:5672//
[2023-01-03 21:39:48,916: INFO/MainProcess] mingle: searching for neighbors
[2023-01-03 21:39:49,957: INFO/MainProcess] mingle: all alone
[2023-01-03 21:39:50,007: INFO/MainProcess] celery@testdeMacBook-Pro.local ready.
其中可以看到配置信息和任务信息。
最后调用任务:
需要调用我们创建的实例任务,可以通过 delay()
进行调用。
delay()
是 apply_async()
的快捷方法,可以更好的控制任务的执行
>>> from tasks import add
>>> add.delay(4, 4)
<AsyncResult: e4722dc5-1ccd-45b5-ba89-75ff3edf4255>
调用任务会返回一个 AsyncResult 的实例,用于检测任务的状态,等待任务完成获取返回值(如果任务执行失败,会抛出异常)。默认这个功能是不开启的,到那时我们配置了backend,所以可以查看任务的状态,如下:
>>> result.ready() # ready() 可以检测是否已经处理完毕:
True
>>> result.get(timeout=1) # get获取任务执行结果
8
如果任务出现异常,可以通过以下命令进行回溯:
>>> result.traceback
同时该任务已经有被celery Worker开始处理,可以在启动celery的控制台输出的日志进行查看执行情况,如下可以看到任务被成功执行:
[2023-01-03 21:48:08,374: INFO/MainProcess] Task tasks.add[1b5f11de-c113-4f07-b2de-52c7f7594959] received
[2023-01-03 21:48:08,390: INFO/ForkPoolWorker-8] Task tasks.add[1b5f11de-c113-4f07-b2de-52c7f7594959] succeeded in 0.013839624999999245s: 8
Flask使用Celery
异步任务
下面来看下在实际flask项目中,如何使用Celery。
1.创建flask项目
使用pycharm创建一个flask项目,名称为flask_celery。
同时创建一个文件夹,名称为celery_tasks,专门用于管理celery相关的文件。
2.celery配置
针对较大型的项目,建议使用专用配置模块,进行针对 Celery 配置。不建议使用硬编码,建议将所有的配置项集中化配置。
需要在celery_tasks文件夹下创建一个名为 config.py
的文件,添加以下配置内容:
broker_url = 'amqp://guest:guest@localhost:5672'
result_backend = 'redis://:123456@localhost:6379/8'
更多配置后面会讲解。
创建完后可以通过 app.config_from_object()
进行加载配置模块。
3.创建Celery app实例
在celery_tasks文件夹下创建main.py文件,代码如下:
from celery import Celery
from celery_tasks import configcelery_app = Celery(__name__)# 加载配置文件
celery_app.config_from_object(config)# 自动搜寻异步任务
celery_app.autodiscover_tasks(['celery_tasks.sms'])
注意:autodiscover_tasks用来自动搜寻我们指定文件夹下创建的任务,但是任务所在的文件必须叫tasks.py。
当然也可以在创建celery对象时使用参数include直接指定搜寻任务文件夹,如下:
celery_app = Celery('tasks',broker='redis://127.0.0.1:6379/1',backend='redis://127.0.0.1:6379/2',include=['celery_tasks.sms',])
4.创建任务
创建一个发送短信验证码的任务:先在celery_tasks文件夹下创建sms文件夹,然后创建一个tasks.py(为了能被自动搜寻到)文件,编辑代码如下:
import timefrom celery_tasks.celery_service import celery_app@celery_app.task
def send_sms(phone, data):"""模拟发送短信"""time.sleep(3)print("发送短信成功")return True
5.创建业务接口
一般真实业务中,我们的任务都是由flask项目中的业务去调用。这里创建一个名称为sms的接口,来调用发送短信验证码的任务,代码如下:
from flask import Flaskfrom celery_tasks.sms_task import send_smsapp = Flask(__name__)@app.route('/')
def hello_world():return 'Hello World!'@app.route('/sms')
def sms():# 做一些业务操作# delay函数会把任务交给celery去执行,然后立即返回,所以是异步send_sms.delay()return 'send sms success!'if __name__ == '__main__':app.run()
6.启动flask项目
启动flask项目即可
7.启动celery
注意,启动时,不要切换到celery_app所在文件夹下,而是在项目根目录即可(后面会说明为什么)。
执行命令:
celery -A celery_tasks.main worker -l info-------------- celery@testdembp v5.2.7 (dawn-chorus)
--- ***** -----
-- ******* ---- macOS-10.16-x86_64-i386-64bit 2023-01-05 00:14:03
- *** --- * ---
- ** ---------- [config]
- ** ---------- .> app: celery_tasks.celery_service:0x7f95f8a69f70
- ** ---------- .> transport: amqp://guest:**@localhost:5672//
- ** ---------- .> results: redis://:**@localhost:6379/8
- *** --- * --- .> concurrency: 8 (prefork)
-- ******* ---- .> task events: OFF (enable -E to monitor tasks in this worker)
--- ***** ----- -------------- [queues].> celery exchange=celery(direct) key=celery[tasks]. celery_tasks.sms.tasks.send_sms[2023-01-05 00:14:04,226: INFO/MainProcess] Connected to amqp://guest:**@127.0.0.1:5672//
[2023-01-05 00:14:04,235: INFO/MainProcess] mingle: searching for neighbors
[2023-01-05 00:14:05,273: INFO/MainProcess] mingle: all alone
[2023-01-05 00:14:05,298: INFO/MainProcess] celery@testdembp ready.
可以看到tasks里已经有我们的celery_tasks.sms.tasks.send_sms任务了,注意这里的任务名就是这个包含路径的全名,而不只是send_sms这个函数名。
注意:正式环境启动时,可以使用如下命令启动celer worker
nohup celery -A proj worker - P gevent -c 1000 > celery.log 2>&1 &# 1.nohup 和末尾的&:后台执行,忽略所有挂断
# 2.- P gevent -c 1000 :开1000个协程执行,可根据业务调整
8.测试
访问我们的sms接口:http://127.0.0.1:5000/sms。然后可以看到接口是立即返回的,没有延迟3秒。然后再celery任务控制台看到如下信息:
[2023-01-05 00:16:54,391: INFO/MainProcess] Task celery_tasks.sms.tasks.send_sms[23b58998-ab44-4bc6-8aff-bc6cc12aa664] received
[2023-01-05 00:16:57,394: WARNING/ForkPoolWorker-8] 发送短信成功
[2023-01-05 00:16:57,402: INFO/ForkPoolWorker-8] Task celery_tasks.sms.tasks.send_sms[23b58998-ab44-4bc6-8aff-bc6cc12aa664] succeeded in 3.0086944159999973s: True
任务被成功执行,且看到最后耗时3.0086944159999973s,返回True。
看一下整个项目的结构如下:
最后特别说明:
整个项目其实由三部分组成:客户端(flask应用)、Celery服务端、中间件(broker)。这三部分在实际成产中都可以分开单独去部署,Celery本身也是一个单独的服务,只不过为了方便,写在了flask项目中,实际也可以把celery_tasks文件夹单独拿出来,单独去部署启动服务。但是文件分开后注意一点,flask客户端去调用celery里的异步任务的时候,是通过任务名(就是上面我们看到的文件路径加函数名组成的)放到Broker中,celery服务从Broker获取任务名去执行。flask可以没有具体的异步任务逻辑代码,只要一个任务名就行,但是为了flask能顺利调用异步任务,flask项目使用celery的相关文件的目录结构要与celery本身服务的目录结构相同,这样保证了flask客户端和celery服务两边的任务名相同。
当celery异步任务中需要flask上下文时,就不宜把flask项目和celery项目分开了。
还有一点是,除非有特殊要求,否则任务最好不要返回值,能省去后端结果存储、提高性能。
定时任务
创建定时任务时,使用celery的celery beat,它是一个调度程序,定期启动任务,然后由集群中的可用节点执行任务。
默认情况下会从配置中的 beat_schedule
项中获取条目(entries,也就是要执行的具体的定时任务),但是也可以使用自定义存储,例如将entries存储在SQL数据库中。
时区设置:默认情况下,定期任务计划使用UTC时区,但是可以使用时区设置更改使用的时区。
例如配置 Asia/Shanghai:
broker_url = 'amqp://guest:guest@localhost:5672'
result_backend = 'redis://:123456@localhost:6379/8'
# 时区设置
timezone = 'Asia/Shanghai'
也可以你直接使用app.conf.timezone ='Asia/Shanghai'
来直接配置。
首先创建我们的任务,在celery_tasks文件夹创建一个新文件夹scheduled,然后创建tasks.py文件,编辑 celery_tasks/scheduled/tasks.py,代码如下:
from celery_tasks.main import celery_app@celery_app.task
def scheduled_task(name):"""模拟定时任务"""print(f"{name}执行定时任务")return True
然后在周期调度列表中添加条目(entry),建议使用如下方式添加,编辑celery_tasks/main.py:
from datetime import timedeltafrom celery import Celery# from app import app
from celery_tasks import configcelery_app = Celery(__name__)# 加载配置文件
celery_app.config_from_object(config)# 自动搜寻异步任务
celery_app.autodiscover_tasks(['celery_tasks.sms', 'celery_tasks.scheduled'])# 设置定时任务
celery_app.conf.beat_schedule = {# 名字,最好做到见名知意'add-every-10-seconds': {# 执行scheduled.tasks下的scheduled_task函数'task': 'celery_tasks.scheduled.tasks.scheduled_task',# 每隔3秒执行一次'schedule': 3.0,# 'schedule': timedelta(seconds=3),# 传递参数'args': ('张三',)},
}
设置时间间隔时,也可以使用timedelta(不仅可以设置秒,也可以设置天,年等间隔),这样更加灵活。
下面启动我们的celery worker服务
celery -A celery_tasks.main worker -l info# 显示如下启动成功-------------- celery@testdembp v5.2.7 (dawn-chorus)
--- ***** -----
-- ******* ---- macOS-10.16-x86_64-i386-64bit 2023-01-07 12:14:20
- *** --- * ---
- ** ---------- [config]
- ** ---------- .> app: celery_tasks.main:0x7fbb2066c3d0
- ** ---------- .> transport: amqp://guest:**@localhost:5672//
- ** ---------- .> results: redis://:**@localhost:6379/8
- *** --- * --- .> concurrency: 8 (prefork)
-- ******* ---- .> task events: OFF (enable -E to monitor tasks in this worker)
--- ***** ----- -------------- [queues].> celery exchange=celery(direct) key=celery[tasks]. celery_tasks.scheduled.tasks.scheduled_task. celery_tasks.sms.tasks.send_sms[2023-01-07 12:14:21,070: INFO/MainProcess] Connected to amqp://guest:**@127.0.0.1:5672//
[2023-01-07 12:14:21,083: INFO/MainProcess] mingle: searching for neighbors
[2023-01-07 12:14:22,119: INFO/MainProcess] mingle: all alone
[2023-01-07 12:14:22,145: INFO/MainProcess] celery@testdembp ready.
这时候是不会执行任何任务的。与一般的异步任务不同的是,定时任务是依赖celery beat
服务的,需要单独再启动celery beat服务,如下:
celery -A celery_tasks.main beat
# 显示如下则启动成功
celery beat v5.2.7 (dawn-chorus) is starting.
__ - ... __ - _
LocalTime -> 2023-01-07 12:07:10
Configuration ->. broker -> amqp://guest:**@localhost:5672//. loader -> celery.loaders.app.AppLoader. scheduler -> celery.beat.PersistentScheduler. db -> celerybeat-schedule. logfile -> [stderr]@%WARNING. maxinterval -> 5.00 minutes (300s)
beat进程会读取配置文件的内容,周期性的将配置中到期需要执行的任务发送给任务队列,然后worker进程从队列读取执行。
启动后,在worker服务的终端马山可以看到任务已经执行了,如下:
[2023-01-07 12:14:28,999: INFO/MainProcess] Task celery_tasks.scheduled.tasks.scheduled_task[64510402-3a67-43f4-b1f3-60477f873e7b] received
[2023-01-07 12:14:29,001: WARNING/ForkPoolWorker-8] 张三执行定时任务
[2023-01-07 12:14:29,008: INFO/ForkPoolWorker-8] Task celery_tasks.scheduled.tasks.scheduled_task[64510402-3a67-43f4-b1f3-60477f873e7b] succeeded in 0.007088375000000369s: True
[2023-01-07 12:14:31,973: INFO/MainProcess] Task celery_tasks.scheduled.tasks.scheduled_task[d81cf939-c24d-4cdd-b111-03bfa4a315b8] received
[2023-01-07 12:14:31,974: WARNING/ForkPoolWorker-8] 张三执行定时任务
[2023-01-07 12:14:31,976: INFO/ForkPoolWorker-8] Task celery_tasks.scheduled.tasks.scheduled_task[d81cf939-c24d-4cdd-b111-03bfa4a315b8] succeeded in 0.0017581670000001992s: True
[2023-01-07 12:14:34,970: INFO/MainProcess] Task celery_tasks.scheduled.tasks.scheduled_task[385e75e0-e9c6-4510-993d-12a82799e5dc] received
[2023-01-07 12:14:34,971: WARNING/ForkPoolWorker-8] 张三执行定时任务
[2023-01-07 12:14:34,972: INFO/ForkPoolWorker-8] Task celery_tasks.scheduled.tasks.scheduled_task[385e75e0-e9c6-4510-993d-12a82799e5dc] succeeded in 0.0008522909999992834s: True
可以看到,确实任务每3秒执行一次。
设置任务时,还可以更加灵活的使用Crontab 调度器,例如一天中的特定时间或一周中的某天执行任务。
如下,设置任务每周一的上午7:30分执行:
from celery.schedules import crontabapp.conf.beat_schedule = {# Executes every Monday morning at 7:30 a.m.'add-every-monday-morning': {'task': 'celery_tasks.scheduled.tasks.scheduled_task','schedule': crontab(hour=7, minute=30, day_of_week=1),'args': ('张三',),},
}
Celery使用Flask上下文
参考:https://flask.palletsprojects.com/en/2.2.x/patterns/celery/
关于Flask的上下文原理参考文章:https://blog.csdn.net/qq_43745578/article/details/129574039?spm=1001.2014.3001.5501
根据Flask上下文原理介绍,我们知道:
在一个非请求的线程中,想要使用应用上下文,必须要 手动把上下文push到栈中,文章中介绍了两种方法。
在Celery执行任务时,也一样,由于Celery是异步的,和请求并不是一个线程,所以Celery要想使用上下文,也需要同样把上下文手动push到栈中。这里我们使用with app.app_context()
。
同时我们需要使用工厂函数模式来创建app
和celery_app
。
修改我们的项目结构如下:
主要变化如下:
1.增加一个app文件夹,用于创建Flaskapp和Celery app
2.celery_tasks
文件夹下的__init__.py
文件增加创建Celery app的工厂方法。
3.增加run.py
取代之前的app.py
,用于启动flask应用。
具体代码如下:
(1)celery_tasks/__init__.py
这个文件增加用来创建Celery app的工厂方法:
from celery import Celery, Task
from flask import Flaskdef celery_init_app(app: Flask) -> Celery:# 重写celery的task类,主要把任务放在上下文中执行class FlaskTask(Task):def __call__(self, *args: object, **kwargs: object) -> object:with app.app_context():return self.run(*args, **kwargs)celery_app = Celery(app.name, task_cls=FlaskTask)# 把celery赋值到app的属性中,便于后面取app.extensions["celery"] = celery_appreturn celery_app
(2)app_factory/__init__.py
这个文件增加flask app的工厂方法,用于创建flask app 和 celery app:
from flask import Flask
from celery_tasks import celery_init_appdef create_app() -> Flask:app = Flask(__name__)celery_init_app(app)return appflask_app = create_app()
celery_app = flask_app.extensions["celery"]
(3)celery_tasks/main.py
修改次文件,不再创建celery app,而是使用app_factory/__init__.py
文件创建的 celery app。
from celery import Celeryfrom celery_tasks import config
from app_factory import celery_app# celery_app = Celery(__name__)# 加载配置文件
celery_app.config_from_object(config)# 自动搜寻异步任务
celery_app.autodiscover_tasks(['celery_tasks.sms', 'celery_tasks.scheduled', 'celery_tasks.context_tasks'])# 设置定时任务
celery_app.conf.beat_schedule = {# 名字,最好做到见名知意'add-every-10-seconds': {# 执行scheduled.tasks下的scheduled_task函数'task': 'celery_tasks.scheduled.tasks.scheduled_task',# 每隔3秒执行一次'schedule': 3.0,# 'schedule': timedelta(seconds=3),# 传递参数'args': ('张三',)},
}
配置文件还和以前一样。
(4)创建celery任务
新建文件夹celery_tasks/context_tasks
,在里面创建文件tasks.py
:
from app_factory import celery_app
from flask import current_app@celery_app.task
def context_task():"""celery中使用flask上下文"""print("context_task")with current_app.app_context():print(f"current_app mysql:{current_app.mysql}")return str(current_app.config)
这里主要创建一个task,并且使用了flask中的应用上下文,打印出来应用的name。
(5)run.py
创建视图函数,启动app:
from app_factory import flask_app as app
from celery_tasks.context_tasks.tasks import context_task
from celery_tasks.sms.tasks import send_sms@app.route('/sms', methods=['GET'])
def sms():send_sms.delay()return 'send sms success!'@app.route('/app_context', methods=["GET"])
def test_flask_app_context():result = context_task.delay()print(result)return "success!"if __name__ == '__main__':app.run()
这里的app使用我们工厂函数创建的app。
(6)启动celery:
celery -A celery_tasks.main worker -l info
(7)测试
访问路由http://127.0.0.1:5000/app_context,看到celery任务后台打印如下:
[2023-03-21 19:04:37,353: INFO/MainProcess] Task celery_tasks.context_tasks.tasks.context_task[70891026-47f7-48b1-bb9c-41aa08be51c3] received
[2023-03-21 19:04:37,356: WARNING/ForkPoolWorker-8] context_task
[2023-03-21 19:04:37,359: WARNING/ForkPoolWorker-8] current_app mysql:mysql1
[2023-03-21 19:04:37,367: INFO/ForkPoolWorker-8] Task celery_tasks.context_tasks.tasks.context_task[70891026-47f7-48b1-bb9c-41aa08be51c3] succeeded in 0.011942791999999702s: '<Config {\'ENV\': \'production\', \'DEBUG\': False, \'TESTING\': False, \'PROPAGATE_EXCEPTIONS\': None, \'PRESERVE_CONTEXT_ON_EXCEPTION\': None, \'SECRET_KEY\': None, \'PERMANENT_SESSION_LIFETIME\': datetime.timedelta(days=31), \'USE_X_SENDFILE\': False, \'SERVER_NAME\': None, \'APPLICATION_ROOT\': \'/\', \'SESSION_COOKIE_NAME\': \'session\', \'SESSION_COOKIE_DOMAIN\': None, \'SESSION_COOKIE_PATH\': None, \'SESSION_COOKIE_HTTPONLY\': True, \'SESSION_COOKIE_SECURE\': False, \'SESSION_COOKIE_SAMESITE\': None, \'SESSION_REFRESH_EACH_REQUEST\': True, \'MAX_CONTENT_LENGTH\': None, \'SEND_FILE_MAX_AGE_DEFAULT\': None, \'TRAP_BAD_REQUEST_ERRORS\': None, \'TRAP_HTTP_EXCEPTIONS\': False, \'EXPLAIN_TEMPLATE_LOADING\': False, \'PREFERRED_URL_SCHEME\': \'http\', \'JSON_AS_ASCII\': True, \'JSON_SORT_KEYS\': True, \'JSONIFY_PRETTYPRINT_REGULAR\': False, \'JSONIFY_MIMETYPE\': \'application/json\', \'TEMPLATES_AUTO_RELOAD\': None, \'MAX_COOKIE_SIZE\': 4093}>'
进阶使用参考
停止Worker
使用 Control + c
就可以停止职程(Worker)
后台运行
正式环境后台启动celery命令:
nohup celery -A proj worker - P gevent -c 1000 > celery.log 2>&1 &# 1.nohup 和末尾的&:后台执行,忽略所有挂断
# 2.- P gevent -c 1000 :开1000个协程执行,可根据业务调整
参考:
https://www.celerycn.io/ru-men/celery-jian-jie
https://blog.csdn.net/u010339879/article/details/97691231
相关文章:
![](https://img-blog.csdnimg.cn/b57aa5589300468aad9cf76fff05346b.png)
Celery使用:优秀的python异步任务框架
目录Celery 简介介绍安装基本使用Flask使用Celery异步任务定时任务Celery使用Flask上下文进阶使用参考停止Worker后台运行Celery 简介 介绍 Celery 是一个简单、灵活且可靠的,处理大量消息的分布式系统,并且提供维护这样一个系统的必需工具。 它是一个…...
![](https://img-blog.csdnimg.cn/02e1244274964107b2ce3c400a3d530e.png)
第十四届蓝桥杯三月真题刷题训练——第 19 天
第 1 题:灌溉_BFS板子题 题目描述 小蓝负责花园的灌溉工作。 花园可以看成一个 n 行 m 列的方格图形。中间有一部分位置上安装有出水管。 小蓝可以控制一个按钮同时打开所有的出水管,打开时,有出水管的位置可以被认为已经灌溉好。 每经过一分…...
![](https://img-blog.csdnimg.cn/img_convert/35edba3b72a0ab22f56bc7f5b0722a85.jpeg)
类和对象 - 下
本文已收录至《C语言》专栏! 作者:ARMCSKGT 目录 前言 正文 初始化列表 成员变量的定义与初始化 初始化列表的使用 变量定义顺序 explicit关键字 隐式类型转换 自定义类型隐式转换 explicit 限制转换 关于static static声明类成员 友元 友…...
![](https://img-blog.csdnimg.cn/513cdcb73d914414aaa71065e8ba9a69.gif#pic_center)
【云原生】Linux基础IO(文件理解与操作)
✨个人主页: Yohifo 🎉所属专栏: Linux学习之旅 🎊每篇一句: 图片来源 🎃操作环境: CentOS 7.6 阿里云远程服务器 Great minds discuss ideas. Average minds discuss events. Small minds disc…...
![](https://www.ngui.cc/images/no-images.jpg)
CentOS 7 安装 mysql 8.0 客户端
只想安装 mysql-client 8.0 , 结果发现直接 yum install mysql mysql-client 安装的版本是 mysql Ver 15.1 Distrib 5.5.68-MariaDB ,这个版本太低,连接其他服务器上的 mysql 8.0 时总是失败,因为 mysql 8.0 加密方式改变了&#…...
![](https://img-blog.csdnimg.cn/img_convert/3b5a0c4bdca64fe4920164cdfe346ac6.png)
Ubuntu下载、配置、安装和编译opencv
1 安装相关依赖安装opencv前,需要先准备好编译器、相关依赖sudo apt-get install gcc g cmake vim sudo apt-get install build-essential libgtk2.0-dev libavcodec-dev libavformat-dev libjpeg-dev libswscale-dev libtiff5-dev sudo apt-get install libgtk2.0-…...
![](https://img-blog.csdnimg.cn/c08bf7a248e346a58b2dc8fe540f9c57.png)
第七讲 贪心
文章目录股票买卖 II货仓选址(贪心:排序中位数)糖果传递(❗贪心:中位数)雷达设备(贪心排序)付账问题(平均值排序❓)乘积最大(排序/双指针)后缀表达…...
![](https://www.ngui.cc/images/no-images.jpg)
数字藏品的未来及发展趋势
随着互联网的普及以及数字文化的日益发展,数字藏品作为一种全新的收藏方式正在逐步兴起。数字藏品可以是数字版权、数字艺术品、数字音乐以及数字视频等形式,这些藏品通过数字化技术保存下来,并在互联网上进行传播和交易。数字藏品的发展趋势…...
![](https://img-blog.csdnimg.cn/17b35b5ed6e64720b913e1f588be6f78.jpeg)
值得记忆的STL常用算法,分分钟摆脱容器调用的困境,以vector为例,其余容器写法类似
STL常用算法 概述: 算法主要是由头文件<algorithm> <functional> <numeric>组成 <algorithm>是所有STL头文件中最大的一个,范围涉及到比较、交换、查找、遍历操作、复制、修改等等 <nuneric>体积很小,只包括…...
java如何手动导jar包
今天用IDEA,需要导入一个Jar包,因为以前都是用eclipse的,所以对这个idea还不怎么上手,连打个Jar包都是谷歌了一下。 但是发现网上谷歌到的做法一般都是去File –> Project Structure中去设置,有没有如同eclipse一样…...
![](https://www.ngui.cc/images/no-images.jpg)
怎么防止SQL注入?
首先SQL注入是一种常见的安全漏洞,黑客可以通过注入恶意代码来攻击数据库和应用程序。以下是一些防止SQL注入的基本措施: 数据库操作层面 使用参数化查询:参数化查询可以防止SQL注入,因为参数化查询会对用户输入的数据进行过滤和…...
![](https://img-blog.csdnimg.cn/d56ca138eacd4b729e9d341d1ad9937c.jpeg)
【千题案例】TypeScript获取两点之间的距离 | 中点 | 补点 | 向量 | 角度
我们在编写一些瞄准、绘制、擦除等功能函数时,经常会遇到计算两点之间的一些参数,那本篇文章就来讲一下两点之间的一系列参数计算。 目录 1️⃣ 两点之间的距离 ①实现原理 ②代码实现及结果 2️⃣两点之间的中点 ①实现原理 ②代码实现及结果 3…...
![](https://img-blog.csdnimg.cn/ea6c74bbf4a04dc78883e0264f7582fd.png)
堆叠注入--攻防世界CTF赛题学习
在一次联系CTF赛题中才了解到堆叠注入,在这里简单介绍一下。 堆叠注入的原理什么的一搜一大堆,我就不引用百度了,直接进入正题。 这个是攻防世界的一道CTF赛题。 采用寻常思路来寻找sql注入漏洞。 payload:1 and 11-- 利用payload: and 12…...
![](https://img-blog.csdnimg.cn/img_convert/d09b30dda49838b5e09488a48d320c60.png)
STM32 ADC+定时器+DMA+FFT
本次实现的功能为单片机DAC输出一个正弦波,然后ADC定时采样用DMA输出,最后对DAC输出的波形进行FFT。单片机STM32F103ZET6内部时钟一、配置ADCADC端口为PA1,采用DMA输出,定时器3触发定时器时钟64M,分频后为102.4KHzADC采…...
![](https://www.ngui.cc/images/no-images.jpg)
用Node.js实现一个HTTP服务器程序(文件服务器)
http Node.js开发的目的就是为了用JavaScript编写Web服务器程序。因为JavaScript实际上已经统治了浏览器端的脚本,其优势就是有世界上数量最多的前端开发人员。如果已经掌握了JavaScript前端开发,再学习一下如何将JavaScript应用在后端开发,就是名副其实的全栈了。 HTTP协…...
![](https://img-blog.csdnimg.cn/227820fabcfc48f98a3f9192febec938.gif)
Python实现人脸识别检测, 对美女主播照片进行评分排名
前言 嗨喽,大家好呀~这里是爱看美女的茜茜呐 素材、视频、代码、插件安装教程我都准备好了,直接在文末名片自取就可点击此处跳转 开发环境: Python 3.8 Pycharm 2021.2 模块使用: requests >>> pip install requests tqdm >…...
![](https://img-blog.csdnimg.cn/5261bf2a11124b798cf2e02aeb0bb25e.png)
【数据结构与算法】什么是双向链表?并用代码手动实现一个双向链表
文章目录一、什么是双向链表二、双向链表的简单实现一、什么是双向链表 我们来看一下这个例子: 在一个教室里,所有的课桌排成一列,如图 相信在你们的读书生涯中,老师肯定有要求你们记住自己的前后桌是谁。所以该例子中&#x…...
![](https://img-blog.csdnimg.cn/3a8e83662fea495baa36475c12c3922c.png)
23种设计模式
参考链接: 【狂神说Java】通俗易懂的23种设计模式教学(停更)_哔哩哔哩_bilibili 23种设计模式【狂神说】_狂神说设计模式_miss_you1213的博客-CSDN博客 1. 单例模式 参考链接: 【狂神说Java】单例模式-23种设计模式系列_哔哩哔哩…...
![](https://www.ngui.cc/images/no-images.jpg)
20美刀一个月的ChatGPT架构师,性价比逆天了
文章目录20美刀一个月的ChatGPT架构师,性价比逆天了1.角色设定2.基本描述3.解决方案4.物理网络蓝图5.系统集成接口5.1 系统集成接口设计5.1.1 前端服务器与后端服务器接口:5.1.2 后端服务器与去背景处理服务接口:5.2 系统集成接口展示6.部署环…...
![](https://www.ngui.cc/images/no-images.jpg)
海门区教育科学规划课题2020年度成果鉴定书
海门区教育科学规划课题2020年度成果鉴定书 课题编号:HMGZ2020007 课题名称 中学历史核心素养校本化实施的培育研究 主持人 徐彬 工作单位 南通市海门证大中学 核心组成员 (包括主持人) 姓名 研究任务完成情况 (获得的主要成果、…...
![](https://www.ngui.cc/images/no-images.jpg)
大数据专业应该怎么学习
大数据学习不能停留在理论的层面上,大数据方向切入应是全方位的,基础语言的学习只是很小的一个方面,编程落实到最后到编程思想。学习前一定要对大数据有一个整体的认识。 大数据是数据量多吗?其实并不是,通过Hadoop其…...
![](https://img-blog.csdnimg.cn/img_convert/2bb8cbc9344106d137781f8b514ef478.jpeg)
学习黑客十余年,如何成为一名高级的安全工程师?
1. 前言 说实话,一直到现在,我都认为绝大多数看我这篇文章的读者最后终究会放弃,原因很简单,自学终究是一种适合于极少数人的学习方法,而且非常非常慢,在这个过程中的变数过大,稍有不慎&#…...
![](https://img-blog.csdnimg.cn/a7d74ccc26644779aefa1e9785b71b86.png)
【算法】手把手学会二分查找
目录 简介 基本步骤 第一种二分 第二种二分 例题 搜索插入位置 数的范围 总结 简介 🥥二分查找,又叫折半查找,通过找到数据二段性每次都能将原来的数据筛选掉一半,通过这个算法我们能够将一个一个查找的 O(n) 的时间复杂…...
![](https://www.ngui.cc/images/no-images.jpg)
SVO、vinsmono、 OKVIS系统比较
几个经典视觉slam系统的比较 SVO 高翔链接:https://www.zhihu.com/question/39904950/answer/138644975处理的各个线程: tracking部分-frame to frame 、frame to map 金字塔的处理。这一步估计是从金字塔的顶层开始,把上一层的结果作为下一层估计的初…...
![](https://www.ngui.cc/images/no-images.jpg)
前端开发规范
一、开发工具 开发工具统一使用 VSCode代码格式化插件使用 Prettier代码格式校验使用 ESLintVSCode 需安装的插件有:ESLint、Prettier、Vetur 二、命名规范 项目命名使用小写字母,以连字符分隔 正确:fe-project 错误:FE PROJECT…...
![](https://img-blog.csdnimg.cn/img_convert/7795cb1f35442887b891cf7b3665a2de.png)
不用科学上网,免费的GPT-4 IDE工具Cursor保姆级使用教程
大家好,我是可乐。 过去的一周,真是疯狂的一周。 GPT-4 震撼发布,拥有了多模态能力,不仅能和GPT3一样进行文字对话,还能读懂图片; 然后斯坦福大学发布 Alpaca 7 B,性能匹敌 GPT-3.5ÿ…...
![](https://www.ngui.cc/images/no-images.jpg)
【艾特淘】抖音小店物流体验分提升的6个维度,新手做店必看
抖音小店体验分,考核的内容包括商品、物流以及服务。大部分人会把重心放在商品评价和服务上,忽略了物流体验。但其实,抖音小店物流体验占比有20%,比服务分的占比还高一点。如果你的订单物流出了问题,很有可能会导致用户…...
![](https://img-blog.csdnimg.cn/9c152e18a85b46f78bb7ca2919c1a56f.png)
数据结构——二叉树与堆
作者:几冬雪来 时间: 内容:二叉树与堆内容讲解 目录 前言: 1.完全二叉树的存储: 2.堆的实现: 1.创建文件: 2.定义结构体: 3.初始化结构体: 4.扩容空间与扩容…...
![](https://img-blog.csdnimg.cn/4076c3bedf0e4d40aff5ac08352a9850.png)
Three.js——learn02
Three.js——learn02Three.js——learn02通过轨道控制器查看物体OrbitControls核心代码index2.htmlindex.cssindex2.jsresult添加辅助器1.坐标轴辅助器AxesHelper核心代码完整代码2.箭头辅助器ArrowHelper核心代码完整代码3.相机视锥体辅助器CameraHelper核心代码完整代码Three…...
![](https://img-blog.csdnimg.cn/img_convert/e992045027882e8f94d70ab26ed681cc.png)
零基础小白如何入门网络安全?
我经常会看到这一类的问题: 学习XXX知识没效果; 学习XXX技能没方向; 学习XXX没办法入门; 给大家一个忠告,如果你完全没有基础的话,前期最好不要盲目去找资料学习,因为大部分人把资料收集好之…...
![](https://img-blog.csdnimg.cn/20200101220807667.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2Rhamlhbmd0YWkwMDc=,size_16,color_FFFFFF,t_70)
电脑制作网站总么做/模板建站和开发网站区别
(一)架构师技能树 大数据基础巩固(录播) HDFS分布式文件系统 1.HDFS架构设计 2.HDFS设计思想 3.数据块 4.机架感知 5.容错策略 6.数据本地性策略 7.读写流程分析 8.HDFS高可用原理 MapReduce分布式计算模型 1.基本原理 2.作业执…...
![](https://img-blog.csdnimg.cn/img_convert/629b8d3e429b1a6f93f9273440e00146.png)
上海高端品牌网站建设/如何弄一个自己的网站
这是我之前项目同学遇到的一个问题,现实代码比较复杂,现在我将尽可能简单的描述这个问题,并且内容重心会放在探索为什么会出现这样的情况以及后续监控。一、问题的起源先看一个非常简单的model类Boy:publicclass Boy {publicString boyName;p…...
![](/images/no-images.jpg)
锦州网站建设更好/百度推广注册
<?xml:namespace prefix o ns "urn:schemas-microsoft-com:office:office" />美国思科公司(Cisco System Inc.)可谓无人不知,无人不晓。凭借它的IOS(Internet Operating System),Cisco公…...
![](/images/no-images.jpg)
ps制作网站首页面教程/如何优化网站推广
之前谈到免货运,真的很难,你想如果是你在网上购买食品,你一般会购买多少?有的人会说,我会很多,但是你在看看食品的价格是多少,也许你购买了一大袋食品价格也许不会超过100块,但是从重…...
![](http://upload.chinaz.com/2012/0221/1329788502593.png)
网站推广专家/百度 seo排名查询
2003年4月7日,马云,在杭州,成立了一个神秘的组织。他叫来十位员工,要他们签了一份协议,这份协议要求他们立刻离开阿里巴巴,去做一个神秘的项目。这个项目要求绝对保密,老马戏称“连说梦话被老婆…...
![](/images/no-images.jpg)
东昌府区建设局网站/公司软文推广
各个参数可参照最后的友链;下面是个异常:2014-09-16 12:45:00.012 [PoolCleaner[326380248:1409911461938]] WARN o.a.tomcat.jdbc.pool.ConnectionPool - Connection has been abandoned PooledConnection[com. mysql.jdbc.JDBC4Connection433b6bee]:java.lang.Ex…...