• django开发傻瓜教程-3-celery异步处理


    Ref:

    https://www.jianshu.com/p/6f8576a37a3e

    https://blog.csdn.net/Demo_3/article/details/78119951

    https://blog.csdn.net/spur_man/article/details/79550917

    https://my.oschina.net/37Y37/blog/1920149

    http://docs.jinkan.org/docs/celery/getting-started/next-steps.html

    https://www.ctolib.com/topics-130539.html#


    为什么选择Celery

    当前的需求是:我用form从前端拿到了提交的数据,由于需要处理一点时间(也许很多用户同时提请求呢)虽然感觉暂时想多了=.=

    如果处理时间过长,那么一方面页面可能会超时,另一方面,用户等待太久也是不合适的。所以现在希望,在用户提交数据后,立刻就

    能收到一个回复(比如说task ID),等到任务结束后,通知用户,用这个ID就可以获取结果(当然可以是服务器靠这个ID来输出结果)。

    我也考虑过用ajax直接部分刷新页面,但是感觉对于长时间的并发任务,可能不是很合适(看到的ajax例子都是很简单的,不是很懂是不是不适合复杂的计算逻辑?)。总之,为了以后的发展,还是学一下水芹菜吧。

    概念

    Celery 的基本架构采用典型的生产者—消费者模式,主要由三部分组成:broker(消息队列)、workers(消费者:处理任务)、backend(存储结果)。Celery自己不提供消息服务,但是可以和提供消息服务的中间件集成。这里推荐的broker有RabbitMQ(官网推荐)和Redis。Workers可以并发地运行在分布式的节点上。
    实际应用时,用户从 Web 前端发起一个请求,然后将请求所要处理的任务丢入 broker中,由空闲的 worker 去处理,处理的结果会暂存在后台数据库 backend 中。
    处理场景

    异步任务处理:例如给注册用户发送短消息或者确认邮件任务。

    大型任务:执行时间较长的任务,例如视频和图片处理,添加水印和转码等,需要执行任务时间长。

    定时执行的任务:支持任务的定时执行和设定时间执行。例如性能压测定时执行。

    安装

    pip install celery

    为了让celery中执行任务的结果返回Django,再装一个

    sudo pip install django-celery-results

    使用redis做broker和backend,安装:

    sudo apt-get install redis
    sudo
    pip install redis

     如果apt-get有错误,请用下面的命令

    sudo apt-get install redis --fix-missing

    开启redis服务

    redis-server

    报错

    我就知道不会一帆风顺的:)

    解决:1. 找到redis-server进程,kill

    2. 接着发现redis-server进程仍然存在,杀不掉:)

    所以使用停止服务的命令。必要的话要用sudo。

    /etc/init.d/redis-server stop

    然后再重启redis-service即可

     现在正式来写Celery了。首先看一下目录结构:

    配置阶段先改celery.py和__init__.py

    # Celery.py
    from __future__ import absolute_import, unicode_literals
    import os
    from celery import Celery, platforms
    
    # set the default Django settings module for the 'celery' program.
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'probe.settings')
    
    app = Celery('probe')
    
    # Using a string here means the worker don't have to serialize
    # the configuration object to child processes.
    # - namespace='CELERY' means all celery-related configuration keys
    #   should have a `CELERY_` prefix.
    app.config_from_object('django.conf:settings', namespace='CELERY')
    
    # Load task modules from all registered Django app configs.
    app.autodiscover_tasks()
    
    # Allow root user run celery
    platforms.C_FORCE_ROOT = True
    
    @app.task(bind=True)
    def debug_task(self):
        print('Request: {0!r}'.format(self.request))

    __init__.py

    from __future__ import absolute_import, unicode_literals
    
    # This will make sure the app is always imported when
    # Django starts so that shared_task will use this app.
    from .celery import app as celery_app
    
    __all__ = ['celery_app']

    然后进入根目录

    celery worker -A probe -l info

    你以为这样就可以了?报错:

    这是因为我们的水芹找不到redis啊:)所以要修改上面的celery.py

    # redis是broker和backend
    app = Celery('probe', backend='redis', broker='redis://localhost')

    现在来配置一下celery。上面的修改暂时取消,我们统一在settings.py里配置celery。

    CELERY_BROKER_URL = 'redis://localhost:6379'
    CELERY_ACCEPT_CONTENT = ['json']
    CELERY_TASK_SERIALIZER = 'json'
    CELERY_RESULT_BACKEND = 'redis'
    CELERY_TIMEZONE = 'Asia/Shanghai'
    CELERYD_MAX_TASKS_PER_CHILD = '1'

      # celery在长时间运行后可能出现内存泄漏,需要添加这个配置,表示每个worker执行了多少个任务就死掉

    # INSTALLED_APPS里再添加一个'django_celery_results'

    然后migrate一下变化

    python manage.py migrate django_celery_results

    现在来真正写任务了:task.py

    这个task.py在每个app下都要有,而且名称不能改变。

    from __future__ import absolute_import, unicode_literals
    from celery import shared_task
    
    @shared_task
    def longtime_test():
    # 在这里写操作

    然后在views.py里(我这里是把design2.py和主页design-post绑在一起的,所以我写到design2.py里去)

    longtime_test.delay()

    补一刀:

    在design2.py里,我这么写(省略其他)这里只是简单测试一下:

    import task
    
    def design_post(request):
        ...
        if request.POST:
            result = task.longtime_test.delay(ctx['target_definition'], ctx['target_species'])
            while True:
                if result.ready():
                    print "celery fried!"
                    break;
        ...

    事实上我第一次遇到了报错

    当时写的是from task import longtime_test

    我改成上面的写法之后,重启celery,就没有报错:celery正确输出字符串(毕竟我只做了字符串连接啊摊手)

    而且django后台这里也正确反馈了(黄色标识)红色的是之前报错状态的显示。因为longtime_test函数一样返回了,所以还是会跳出循环。

     好了我现在要去写业务代码了,配置方面的任务暂时告一段落:)

  • 相关阅读:
    sizeof in C
    Get WIFI SSID and BSSID
    Swift和C混合Socket编程实现简单的ping命令&主机发现
    The different of bit Compiler
    Get all Ethernet information in Swift
    Get Local IP Address in Swift
    编译Unity3D Mono 加密DLL 填坑记
    spring-quartz 项目启动后执行一次job 之后按照规定时间执行job
    通过反射获取SSM的controller层的注解以及注解中的value值
    网页中高亮选中的关键字
  • 原文地址:https://www.cnblogs.com/pxy7896/p/9930377.html
Copyright © 2020-2023  润新知