子进程阻止 Django 视图

发布于 2024-10-15 10:06:02 字数 2477 浏览 1 评论 0原文

我从视图调用 subprocess.Popen 时遇到问题: 在子流程完成之前,不会显示调用 subprocess.Popen 的视图。 服务器立即发送“200 OK”,但不发送页面内容。

我的问题是:这是 Django 开发服务器的限制还是我做错了?

服务器不会完全挂起,因为同时可以处理其他视图。

已经有关于该主题的一些问题,Google 给出了一些其他线程,但我找不到我的问题的明确答案。

我相信这不是 python 问题,因为此命令立即终止:

python -c '导入子进程;打印 subprocess.Popen(["/bin/sleep", "10"]).pid'

如何重现

创建测试项目 &应用程序:

cd /tmp
django-admin.py 启动项目 django_test
cd django_test
./manage.py startapp subprocess_test

替换 urls.py & subprocess_test/views.py 包含:

  • urls.py:

    从 django.conf.urls.defaults 导入 *

    urlpatterns = 模式('',
      (r'^hello$', 'subprocess_test.views.hello'),
      (r'^start$', 'subprocess_test.views.start'),
    )

  • subprocess_test/views.py

    从 django.http 导入 HttpResponse

    导入子进程

    def 你好(请求):
     返回 HttpResponse('你好世界!')

    def 开始(请求):
      subprocess.Popen(["/bin/sleep", "10"])
      return HttpResponse('start done')

测试一下:

./manage.py runserver 0.0.0.0:8000

转到 http://127.0.0.1:8000/hello 和 http://127.0.0.1:8000/start

测试结果

“start”需要10s load 和“hello”可以在这段时间内加载。 例如,我得到这样的日志:

[2011年2月1日07:20:57]“GET /hello HTTP/1.1”200 12
[2011 年 2 月 1 日 07:21:01]“GET /启动 HTTP/1.1”200 10
[2011 年 2 月 1 日 07:21:01]“GET /hello HTTP/1.1”200 12
[01/2/2011 07:21:02]“GET /hello HTTP/1.1”200 12

使用 wget:

wget http://127.0.0.1:8000/start
--2011-02-01 14:31:11-- http://127.0.0.1:8000/start< /a>
正在连接到 127.0.0.1:8000...已连接。
HTTP 请求已发送,正在等待响应...200 OK
长度:未指定 [text/html]
保存到:`开始'

<前><代码>[ <=>; ] 9,5 秒内 10 --.-K/s

2011-02-01 14:31:21(1,05 B/s)-“开始”已保存[10]

I have a problem calling subprocess.Popen from a view:
The view that calls subprocess.Popen is not displayed until the subprocess finishes.
The server send "200 OK" immediately, but not the content of the page.

My question is: Is this a limitation of Django's development server or am I doing it wrong?

The server does not completely hangs, as other views can be processed in the meantime.

There are already a few questions on that topic and Google gives a few other threads, but I cannot find a clear answer to my question.

I believe this is not a python issue as this commands terminate immediately:

python -c 'import subprocess; print subprocess.Popen(["/bin/sleep", "10"]).pid'

How to reproduce

Create test project & app:

cd /tmp
django-admin.py startproject django_test
cd django_test
./manage.py startapp subprocess_test

Replace urls.py & subprocess_test/views.py with:

  • urls.py:

    from django.conf.urls.defaults import *

    urlpatterns = patterns('',
      (r'^hello$', 'subprocess_test.views.hello'),
      (r'^start$', 'subprocess_test.views.start'),
    )

  • subprocess_test/views.py

    from django.http import HttpResponse

    import subprocess

    def hello(request):
      return HttpResponse('Hello world!')

    def start(request):
      subprocess.Popen(["/bin/sleep", "10"])
      return HttpResponse('start done')

Test it:

./manage.py runserver 0.0.0.0:8000

Go to http://127.0.0.1:8000/hello and http://127.0.0.1:8000/start

Test result

"start" takes 10s to load and "hello" can be loaded during that time.
For example, I get such a log:

[01/Feb/2011 07:20:57] "GET /hello HTTP/1.1" 200 12
[01/Feb/2011 07:21:01] "GET /start HTTP/1.1" 200 10
[01/Feb/2011 07:21:01] "GET /hello HTTP/1.1" 200 12
[01/Feb/2011 07:21:02] "GET /hello HTTP/1.1" 200 12

Using wget:

wget http://127.0.0.1:8000/start
--2011-02-01 14:31:11-- http://127.0.0.1:8000/start
Connecting to 127.0.0.1:8000... connected.
HTTP request sent, awaiting response... 200 OK
Length: unspecified [text/html]
Saving to: `start'

[           <=>                           ] 10          --.-K/s   in 9,5s    

2011-02-01 14:31:21 (1,05 B/s) - « start » saved [10]

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

暖伴 2024-10-22 10:06:02

看起来您并不关心系统调用的结果是什么,所以我假设您正在尝试进行某种离线(或后台)处理。

我建议采用一种更干净的方法来解决这个问题,而不是直接执行程序。使用排队系统(例如 Gearman)对处理任务进行排队,然后使用一个单独的工作线程来消耗队列中的项目。

这样做的优点是可以在发生大流量峰值时保护您的服务器,因此您不必在每次向该视图发出请求时分叉进程。您可以根据自己的决定慢或快地消费物品,而不受流量的影响。

交通可能不是问题,但我个人认为这也是一个更简洁的设计决策。

It looks like you don't care what the result of the system call is, so I would assume you are trying to do some sort of offline(or background) processing.

I would suggest a cleaner way of going about it rather than directly executing a program. Use a queueing system such as Gearman to queue up processing tasks and then have a separate worker that consumes items from the queue.

This has the advantage of protecting your server when large traffic spikes happen, so you don't fork off a process each time a request to that view is made. You can consume items as slow or as fast as you decide, independent of traffic.

Traffic may not be an issue, but I personally think it is a cleaner design decision as well.

少钕鈤記 2024-10-22 10:06:02

我在使用 nginx+uwsgi 运行 Django 时遇到了同样的问题。通常断点是网络服务器的模块,在我的例子中它是uwsgi。添加 解决了这个问题。从另一方面来说,fastcgi 模块不会导致视图挂在后台进程上。

我不知道您使用哪个服务器,因此您可以使用各种模块(uwsgi、mod_wsgi、fastcgi)检查此行为,然后看看哪个更适合您。
并尝试在后台执行:

subprocess.Popen(["/bin/sleep", "10", "&"])

I encountered the same problem running Django with nginx+uwsgi. Often the breaking point is the module of web-server, in my case it was uwsgi. Adding <close-on-exec/> solved this problem. From other side the fastcgi module doesn't cause to view to hung on background processes.

I don't know which server do you use, so you can check this behavior with various modules (uwsgi, mod_wsgi, fastcgi) and see what is more suitable for you.
And try to execute in background:

subprocess.Popen(["/bin/sleep", "10", "&"])
長街聽風 2024-10-22 10:06:02

试试这个

import subprocess

x = subprocess.Popen(["/bin/sleep", "10"])
x.wait()

Try this

import subprocess

x = subprocess.Popen(["/bin/sleep", "10"])
x.wait()
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文