Django:在后台线程中启动一个进程?

时间:2022-04-07 20:30:01

I'm trying to work out how to run a process in a background thread in Django. I'm new to both Django and threads, so please bear with me if I'm using the terminology wrong.

我正在尝试研究如何在Django的后台线程中运行一个进程。我是Django和线程的新手,所以如果我使用的术语错了,请耐心等待。

Here's the code I have. Basically I'd like start_processing to begin as soon as the success function is triggered. However start_processing is the kind of function that could easily take a few minutes or fail (it's dependent on an external service over which I have no control), and I don't want the user to have to wait for it to complete successfully before the view is rendered. ('Success' as far as they are concerned isn't dependent on the result of start_processing; I'm the only person who needs to worry if it fails.)

这是我的代码。基本上我希望start_processing在触发成功函数后立即开始。然而,start_processing是一种很容易花费几分钟或失败的功能(它依赖于我无法控制的外部服务),我不希望用户必须等待它才能成功完成。视图呈现。 (就他们而言,“成功”并不取决于start_processing的结果;如果失败,我是唯一需要担心的人。)

def success(request, filepath):
    start_processing(filepath)
    return render_to_response('success.html', context_instance = RequestContext(request))

From the Googling I've done, most people suggest that background threads aren't used in Django, and instead a cron job is more suitable. But I would quite like start_processing to begin as soon as the user gets to the success function, rather than waiting until the cron job runs. Is there a way to do this?

从谷歌搜索我已经完成,大多数人建议在Django中不使用后台线程,而是cron作业更合适。但是我希望start_processing一旦用户进入成功函数就开始,而不是等到cron作业运行。有没有办法做到这一点?

4 个解决方案

#1


5  

I'm not sure you need a thread for that. It sounds like you just want to spawn off a process, so look into the subprocess module.

我不确定你需要一个线程。听起来你只想生成一个进程,所以请查看子进程模块。

#2


19  

If you really need a quick hack, simply start a process using subprocess.

如果您真的需要快速入侵,只需使用子进程启动进程即可。

But I would not recommend spawning a process (or even a thread), especially if your web site is public: in case of high load (which could be "natural" or the result of a trivial DoS attack), you would be spawning many processes or threads, which would end up using up all your system resources and killing your server.

但我不建议产生一个进程(甚至一个线程),特别是如果你的网站是公共的:如果负载很高(可能是“自然的”或者是一个简单的DoS攻击的结果),你会产生很多进程或线程,最终会耗尽所有系统资源并终止服务器。

I would instead recommend using a job server: I use Celery (with Redis as the backend), it's very simple and works just great. You can check out many other job servers, such as RabbitMQ or Gearman. In your case, a job server might be overkill: you could simply run Redis and use it as a light-weight message server. Here is an example of how to do this.

我建议使用作业服务器:我使用Celery(Redis作为后端),它非常简单,效果很好。您可以查看许多其他作业服务器,例如RabbitMQ或Gearman。在您的情况下,作业服务器可能有点过分:您可以简单地运行Redis并将其用作轻量级消息服务器。以下是如何执行此操作的示例。

Cheers

干杯

#3


9  

In case someone really wants to run another thread

如果有人真的想要运行另一个线程

def background_process():
    import time
    print("process started")
    time.sleep(100)
    print("process finished")

def index(request):
    import threading
    t = threading.Thread(target=background_process, args=(), kwargs={})
    t.setDaemon(True)
    t.start()
    return HttpResponse("main thread content")

This will return response first, then print "process finished" to console. So user will not face any delay.

这将首先返回响应,然后将“process finished”打印到控制台。因此用户不会遇到任何延迟。

Using Celery is definitely a better solution. However, installing Celery could be unnecessary for a very small project with a limited server etc.

使用Celery绝对是一个更好的解决方案。但是,对于服务器数量有限的非常小的项目,安装Celery可能是不必要的。

You may also need to use threads in a big project. Because running Celery in all your servers is not a good idea. Then there won't be a way to run a separate process in each server. You may need threads to handle this case. File system operations might be an example. It's not very likely though and it is still better to use Celery with long running processes.

您可能还需要在大型项目中使用线程。因为在所有服务器上运行Celery并不是一个好主意。然后,将无法在每个服务器中运行单独的进程。您可能需要线程来处理这种情况。文件系统操作可能是一个例子。虽然这种情况不太可能,但使用长期运行的Celery仍然会更好。

Use wisely.

明智地使用。

#4


3  

IIUC, The problem here is that the webserver process might not like extra long-running threads, it might kill/spawn server processes as demand go up and down, etc etc.

IIUC,这里的问题是webserver进程可能不喜欢额外的长时间运行的线程,它可能会随着需求的上升和下降而杀死/生成服务器进程等。

You're probably better of by communicating to an external service process for this type of processing, instead of embedding it in in the webserver's wsgi/fastcgi process.

通过与外部服务进程通信进行此类处理,您可能更好,而不是将其嵌入到Web服务器的wsgi / fastcgi进程中。

If the only thing you're sending over is the filepath, it ought to be pretty easy to write that service app.

如果您发送的唯一内容是文件路径,那么编写该服务应用程序应该非常容易。

#1


5  

I'm not sure you need a thread for that. It sounds like you just want to spawn off a process, so look into the subprocess module.

我不确定你需要一个线程。听起来你只想生成一个进程,所以请查看子进程模块。

#2


19  

If you really need a quick hack, simply start a process using subprocess.

如果您真的需要快速入侵,只需使用子进程启动进程即可。

But I would not recommend spawning a process (or even a thread), especially if your web site is public: in case of high load (which could be "natural" or the result of a trivial DoS attack), you would be spawning many processes or threads, which would end up using up all your system resources and killing your server.

但我不建议产生一个进程(甚至一个线程),特别是如果你的网站是公共的:如果负载很高(可能是“自然的”或者是一个简单的DoS攻击的结果),你会产生很多进程或线程,最终会耗尽所有系统资源并终止服务器。

I would instead recommend using a job server: I use Celery (with Redis as the backend), it's very simple and works just great. You can check out many other job servers, such as RabbitMQ or Gearman. In your case, a job server might be overkill: you could simply run Redis and use it as a light-weight message server. Here is an example of how to do this.

我建议使用作业服务器:我使用Celery(Redis作为后端),它非常简单,效果很好。您可以查看许多其他作业服务器,例如RabbitMQ或Gearman。在您的情况下,作业服务器可能有点过分:您可以简单地运行Redis并将其用作轻量级消息服务器。以下是如何执行此操作的示例。

Cheers

干杯

#3


9  

In case someone really wants to run another thread

如果有人真的想要运行另一个线程

def background_process():
    import time
    print("process started")
    time.sleep(100)
    print("process finished")

def index(request):
    import threading
    t = threading.Thread(target=background_process, args=(), kwargs={})
    t.setDaemon(True)
    t.start()
    return HttpResponse("main thread content")

This will return response first, then print "process finished" to console. So user will not face any delay.

这将首先返回响应,然后将“process finished”打印到控制台。因此用户不会遇到任何延迟。

Using Celery is definitely a better solution. However, installing Celery could be unnecessary for a very small project with a limited server etc.

使用Celery绝对是一个更好的解决方案。但是,对于服务器数量有限的非常小的项目,安装Celery可能是不必要的。

You may also need to use threads in a big project. Because running Celery in all your servers is not a good idea. Then there won't be a way to run a separate process in each server. You may need threads to handle this case. File system operations might be an example. It's not very likely though and it is still better to use Celery with long running processes.

您可能还需要在大型项目中使用线程。因为在所有服务器上运行Celery并不是一个好主意。然后,将无法在每个服务器中运行单独的进程。您可能需要线程来处理这种情况。文件系统操作可能是一个例子。虽然这种情况不太可能,但使用长期运行的Celery仍然会更好。

Use wisely.

明智地使用。

#4


3  

IIUC, The problem here is that the webserver process might not like extra long-running threads, it might kill/spawn server processes as demand go up and down, etc etc.

IIUC,这里的问题是webserver进程可能不喜欢额外的长时间运行的线程,它可能会随着需求的上升和下降而杀死/生成服务器进程等。

You're probably better of by communicating to an external service process for this type of processing, instead of embedding it in in the webserver's wsgi/fastcgi process.

通过与外部服务进程通信进行此类处理,您可能更好,而不是将其嵌入到Web服务器的wsgi / fastcgi进程中。

If the only thing you're sending over is the filepath, it ought to be pretty easy to write that service app.

如果您发送的唯一内容是文件路径,那么编写该服务应用程序应该非常容易。