进程process:系统级别分配和调度CPU资源,os通过调度算法保存当前的上下文,然后再从当前位置再次开始计算,重新开始的地方不可预期,一个进程至少包含一个线程
线程thread:CPU调度的最小单位,不可以单独运行,必须依附于应用程序
协程eventlet:编译器级别使得代码可以分段式的执行,可以停在指定的位置然后等下一次CPU时间片到来时继续执行,几乎没有开销,适合在短时间内处理大量重复数据
创建进程的进程是父进程,新产生的进程是子进程,父进程可以和子进程同时运行,但父进程终止子进程必须同时终止,(这个过程可以想象成在一个网页可以打开多个听歌,看视频的进程,但当关闭网页由其打开的其他进程同时终止)
import evenlet
@app.task
def task(devices):
#devices = [{"ip": "1.1.1.1", "community": "cisco"}, {"ip": "2.2.2.2", "community": "cisco"}]
try:
此处指定协程池pool的大小
pile = evenlet.GreenPile(len(devices))
for device in devices:
# 此处并发执行reach这个方法,后面接参数
pile.spawn(reach, device['ip'], device['community'])
for resp in pile:
遍历每个执行的结果返回
response.append(resp)
except Exception:
response = []
def reach(ip, community):
pass
调用
第一个参数:执行文件的路径,就是上述代码的位置
第二个参数:传递的参数,注意是个元组,后面必须加逗号
celery_app.send_task('xxx.worker.tasks.task', (abc, ))
当主进程执行到celery并不会等待其的执行结果,而是继续执行下面的代码块,同时产生子进程在后台调用协程来执行
from celery import Celery
# include里指定task文件位置
app = Celery('tasks', include=['xxx.worker.tasks'])
app.config_from_object('xxx.celeryconfig')
celeryconfig.py
CELERY_IMPORTS = ('worker.tasks',)
# 指定时区和broker
CELERY_TIMEZONE = 'Asia/Shanghai'
CELERY_BROKER = 'amqp://localhost'
# 创建三个队列,一个是默认队列,一个是cat、一个dog
CELERY_QUEUES = (
Queue('default', Exchange("default"), routing_key='r_default'),
Queue('cat', Exchange("cat"), routing_key='r_cat'),
Queue('dog', Exchange("dog"), routing_key='r_dog')
)
# 为每个task指定队列,消息到达时指定worker来处理
# 第一个参数:task文件的cat方法
# 第二个参数:绑定的queue
# 第三个参数:绑定的key
CELERY_ROUTES = ({'tasks.cat': {
'queue': 'default',
'routing_key': 'r_default'
}},{'tasks.cat': {
'queue': 'cat',
'routing_key': 'r_cat'
}},{'tasks.dog': {
'queue': 'dog',
'routing_key': 'r_dog'
}}, )
启动worker
celery worker -Q default --loglevel=info -name default -f xxx(指定log位置)
celery worker -Q cat --loglevel=info -name cat -f xxx(指定log位置)