zoukankan      html  css  js  c++  java
  • gunicorn结合django启动后台线程

    preload 为True的情况下,会将辅助线程或者进程开在master里,加重master的负担(master最好只是用来负责监听worker进程)

    django应用的gunicorn示例:只在主线程里开启后台线程,worker里不启动后台线程

    gunicorn -w 5 --preload -b 127.0.0.1:8088 application_name.wsgi:application

    wsgi.py文件:

    """
    WSGI config for erebus project.
    
    It exposes the WSGI callable as a module-level variable named ``application``.
    
    For more information on this file, see
    https://docs.djangoproject.com/en/2.1/howto/deployment/wsgi/
    """
    
    import os
    
    from django.core.wsgi import get_wsgi_application
    from erebus.get_wsgi_application import get_wsgi_application
    from whitenoise import WhiteNoise
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'erebus.settings')
    
    application = get_wsgi_application()
    application = WhiteNoise(application, root='./static/')
    # application.add_files('/path/to/more/static/files', prefix='more-files/')

    重写的get_wsgi_application.py文件:

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    """
        @Author      : xxxxx
        
        @Date        : 2019-02-27 19:26
        
        @Description : 本文件的作用描述
        
        @File        : get_wsgi_application.py 
    """
    
    import django
    from django.core.handlers.wsgi import WSGIHandler
    
    
    def get_wsgi_application():
        """
        The public interface to Django's WSGI support. Return a WSGI callable.
    
        Avoids making django.core.handlers.WSGIHandler a public API, in case the
        internal WSGI implementation changes or moves in the future.
        """
        django.setup(set_prefix=False)
        # 把主进程中的kafka consumer线程放入启动过程中(即放入gunicorn的master进程中),
        # 以使用gunicorn的preload参数控制这些线程的启动个数。
        from utils.kafka_consumer_daemon import start_kafka_consumer_daemon
        start_kafka_consumer_daemon()
        return WSGIHandler()

    后台线程:

    # 使用线程池子
    def start_kafka_consumer_daemon():
        try:
            for _ in range(CONSUMER_THREAD_NUM):
                consumer = threading.Thread(target=consume_kafka)
                consumer.setDaemon(True)
                consumer.start()
        except Exception as e:
            logger.error(e)
            logger.error(traceback.format_exc())

    配置参考:https://github.com/benoitc/gunicorn/blob/29f0394cdd381df176a3df3c25bb3fdd2486a173/examples/example_config.py

    配置解读:http://docs.gunicorn.org/en/stable/settings.html

    Gunicorn+Flask中重复启动后台线程问题

    假设程序如下:

    1 if __name__ == '__main__':
    2     t = Thread(target=test)
    3     t.start()
    4     app.run(host='0.0.0.0',port=8080,debug=False)

          gunicorn在启动过程只会从flask的app文件中取出app使用,并不会执行main函数,如果希望在gunicorn中仍旧能启动后台线程并保证后台线程不因为gunicorn的子进程重复执行,有三种方式。

    1.  使用gunicorn的preload参数。在worker进程被复制(派生)之前载入应用的代码。这种方式,线程执行代码需要写在app文件的全局部分,利用预加载只执行一下。

    2. 使用flask的app的钩子函数before_first_request。在before_first_request中执行线程。但这种方式必须要有第一个请求才能触发线程启动。

    3. 使用文件锁。这种方式与第一种方式相同,需要把线程执行的代码写在app文件的全局部分。在第一个子进程启动时创建文件并加锁,在后续的子进程启动时判断锁的状态,如果有锁则不执行。

       以上通过奇怪的操作启动后台线程。但不推荐。可以考虑使用celery或者cron等方式实现需求。

    参考:

    1、https://www.jianshu.com/p/509985f98416

    2、https://www.cnblogs.com/chenxianpao/p/9931483.html

    3、

    4、

  • 相关阅读:
    (4)Maven快速入门_4在Spring+SpringMVC+MyBatis+Oracle+Maven框架整合运行在Tomcat8中
    (3)Maven快速入门_3在Eclipse中创建Maven项目打包成jar
    (2)Maven快速入门_2maven在Eclipse中的设置
    (1)Maven快速入门_1maven安装
    (11)Microsoft office Word 2013版本操作入门_word中表格操作
    (10)Microsoft office Word 2013版本操作入门_word表格
    洛谷 P2144 [FJOI2007]轮状病毒
    洛谷 P2234 [HNOI2002]营业额统计
    【模板】主席树
    洛谷 P2572 [SCOI2010]序列操作
  • 原文地址:https://www.cnblogs.com/shengulong/p/10472927.html
Copyright © 2011-2022 走看看