首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >Python Django异步请求处理

Python Django异步请求处理
EN

Stack Overflow用户
提问于 2015-09-12 16:30:07
回答 3查看 31.3K关注 0票数 12

我在一个应用程序中工作,我正在做一个巨大的数据处理,以生成一个全新的数据集,然后最终保存到数据库中。应用程序在处理数据和将数据保存到数据库中花费了大量的时间。我想在一定程度上改善用户体验,首先将用户重定向到结果页面,然后在后台进行数据保存部分(可能是以异步方式)。我的问题是,为了显示结果页面,我需要有一组新的处理过的数据。有没有办法让数据处理和数据保存部分在后台完成,每当数据处理部分完成(保存到数据库之前),我就会在结果页中得到处理后的数据?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2015-09-12 18:17:45

异步任务可以使用Celery在Python中完成。您可以简单地将任务推送到芹菜队列中,任务将以异步方式执行。然后,您可以从结果页面执行一些轮询,以检查是否已完成。

其他选择可以是像Tornado这样的东西。

票数 10
EN

Stack Overflow用户

发布于 2018-02-03 03:46:10

另一种策略是编写一个线程类,它启动您编写的自定义管理命令,使其表现为工作线程。这可能比使用芹菜之类的东西要轻一点,当然也有优点和缺点。在应用程序启动期间,我还使用了这种技术来对迁移生成/应用程序进行排序/自动化(因为它位于管道中)。然后,我的gunicorn启动脚本根据需要在pre_exec()或when_ready()等中启动这些线程,然后在on_exit()中停止它们。

# Description: Asychronous Worker Threading via Django Management Commands
# Lets you run an arbitrary Django management command, either a pre-baked one like migrate,
# or a custom one that you've created, as a worker thread, that can spin forever, or not.
# You can use this to take care of maintenance tasks at start-time, like db migration,
# db flushing, etc, or to run long-running asynchronous tasks.  
# I sometimes find this to be a more useful pattern than using something like django-celery,
# as I can debug/use the commands I write from the shell as well, for administrative purposes.

import json
import os
import requests
import sys
import time
import uuid
import logging
import threading
import inspect
import ctypes

from django.core.management import call_command
from django.conf import settings

class DjangoWorkerThread(threading.Thread):
    """
    Initializes a seperate thread for running an arbitrary Django management command.  This is
    one (simple) way to make asynchronous worker threads.  There exist richer, more complex
    ways of doing this in Django as well (django-cerlery).

    The advantage of this pattern is that you can run the worker from the command line as well,
    via manage.py, for the sake of rapid development, easy testing, debugging, management, etc.

    :param commandname: name of a properly created Django management command, which exists
        inside the app/management/commands folder in one of the apps in your project.

    :param arguments: string containing command line arguments formatted like you would
        when calling the management command via manage.py in a shell

    :param restartwait: integer seconds to wait before restarting worker if it dies,
        or if a once-through command, acts as a thread-loop delay timer
    """

    def __init__(self, commandname,arguments="",restartwait=10,logger=""):
        super(DjangoWorkerThread, self).__init__()
        self.commandname = commandname
        self.arguments = arguments
        self.restartwait = restartwait
        self.name = commandname
        self.event = threading.Event()
        if logger:
            self.l = logger
        else:
            self.l = logging.getLogger('root')

    def run(self):
        """
        Start the thread.
        """

        try:
            exceptioncount = 0
            exceptionlimit = 10
            while not self.event.is_set():
                try:
                    if self.arguments:
                        self.l.info('Starting ' + self.name + '  worker thread with arguments ' + self.arguments)
                        call_command(self.commandname,self.arguments)
                    else:
                        self.l.info('Starting ' + self.name + '  worker thread with no arguments')
                        call_command(self.commandname)
                    self.event.wait(self.restartwait)

                except Exception as e:
                    self.l.error(self.commandname + ' Unkown error: {}'.format(str(e)))
                    exceptioncount += 1
                    if exceptioncount > exceptionlimit:
                        self.l.error(self.commandname + " : " + self.arguments + " : Exceeded exception retry limit, aborting.")
                        self.event.set()
        finally:
            self.l.info('Stopping command: ' + self.commandname + " " + self.arguments)

    def stop(self):
        """Nice Stop

        Stop nicely by setting an event.
        """
        self.l.info("Sending stop event to self...")
        self.event.set()
        #then make sure it's dead...and schwack it harder if not.
        #kill it with fire!  be mean to your software.  it will make you write better code.
        self.l.info("Sent stop event, checking to see if thread died.")
        if self.isAlive():
            self.l.info("Still not dead, telling self to murder self...")
            time.sleep( 0.1 )
            os._exit(1)

def start_worker(command_name, command_arguments="", restart_wait=10,logger=""):
    """
    Starts a background worker thread running a Django management command. 

    :param str command_name: the name of the Django management command to run,
        typically would be a custom command implemented in yourapp/management/commands,
        but could also be used to automate standard Django management tasks
    :param str command_arguments: a string containing the command line arguments 
        to supply to the management command, formatted as if one were invoking
        the command from a shell
    """
    if logger:
        l = logger
    else:
        l = logging.getLogger('root')

    # Start the thread
    l.info("Starting worker: "+ command_name + " : " + command_arguments + " : " + str(restart_wait) )
    worker = DjangoWorkerThread(command_name,command_arguments, restart_wait,l)
    worker.start()
    l.info("Worker started: "+ command_name + " : " + command_arguments + " : " + str(restart_wait) )

    # Return the thread instance
    return worker

#<----------------------------------------------------------------------------->

def stop_worker(worker,logger=""):
    """
    Gracefully shutsdown the worker thread 

    :param threading.Thread worker: the worker thread object
    """
    if logger:
        l = logger
    else:
        l = logging.getLogger('root')

    # Shutdown the thread
    l.info("Stopping worker: "+ worker.commandname + " : " + worker.arguments + " : " + str(worker.restartwait) )
    worker.stop()        
    worker.join(worker.restartwait)
    l.info("Worker stopped: "+ worker.commandname + " : " + worker.arguments + " : " + str(worker.restartwait) )
票数 6
EN

Stack Overflow用户

发布于 2015-09-13 00:06:05

这与同步请求的过程相同。您将使用应该返回JsonResponseView。“棘手”的部分是在客户端,在那里你必须对视图进行异步调用。

票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/32536799

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档