子进程阻止 Django 视图
我从视图调用 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
<前><代码>[ <=>; ] 9,5 秒内 10 --.-K/s
--2011-02-01 14:31:11-- http://127.0.0.1:8000/start< /a>
正在连接到 127.0.0.1:8000...已连接。
HTTP 请求已发送,正在等待响应...200 OK
长度:未指定 [text/html]
保存到:`开始'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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
看起来您并不关心系统调用的结果是什么,所以我假设您正在尝试进行某种离线(或后台)处理。
我建议采用一种更干净的方法来解决这个问题,而不是直接执行程序。使用排队系统(例如 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.
我在使用 nginx+uwsgi 运行 Django 时遇到了同样的问题。通常断点是网络服务器的模块,在我的例子中它是uwsgi。添加
解决了这个问题。从另一方面来说,fastcgi 模块不会导致视图挂在后台进程上。我不知道您使用哪个服务器,因此您可以使用各种模块(uwsgi、mod_wsgi、fastcgi)检查此行为,然后看看哪个更适合您。
并尝试在后台执行:
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:
试试这个
Try this