子进程阻塞Django视图
我在调用subprocess.Popen时遇到了问题:调用这个函数的视图在子进程完成之前不会显示。服务器会立即发送“200 OK”,但页面内容却没有。
我想问的是:这是Django开发服务器的限制,还是我做错了什么?
服务器并没有完全挂掉,因为其他视图在这段时间内可以正常处理。
关于这个话题已经有一些问题,谷歌也给出了其他一些讨论,但我找不到明确的答案。
我认为这不是Python的问题,因为这些命令会立即结束:
python -c 'import subprocess; print subprocess.Popen(["/bin/sleep", "10"]).pid'
如何复现这个问题
创建测试项目和应用:
cd /tmp
django-admin.py startproject django_test
cd django_test
./manage.py startapp subprocess_test
用以下内容替换urls.py和subprocess_test/views.py:
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')
测试一下:
./manage.py runserver 0.0.0.0:8000
访问 http://127.0.0.1:8000/hello 和 http://127.0.0.1:8000/start
测试结果
“start”需要10秒才能加载,而在这段时间内“hello”可以正常加载。例如,我得到了这样的日志:
[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
使用wget测试:
wget http://127.0.0.1:8000/start
--2011-02-01 14:31:11-- http://127.0.0.1:8000/start
正在连接到127.0.0.1:8000... 已连接。
HTTP请求已发送,等待响应... 200 OK
长度:未指定 [text/html]
正在保存到: `start'[ <=> ] 10 --.-K/s in 9,5s
2011-02-01 14:31:21 (1,05 B/s) - « start » 已保存 [10]
3 个回答
试试这个
import subprocess
x = subprocess.Popen(["/bin/sleep", "10"])
x.wait()
我在用Django配合nginx和uwsgi的时候也遇到了同样的问题。通常,问题出在网络服务器的模块上,在我这儿是uwsgi模块。添加了<close-on-exec/>
后,这个问题就解决了。另一方面,fastcgi模块不会导致视图在后台进程中卡住。
我不知道你用的是哪个服务器,所以你可以试着用不同的模块(比如uwsgi、mod_wsgi、fastcgi)来检查一下这个问题,看看哪个更适合你。
另外,试着在后台执行:
subprocess.Popen(["/bin/sleep", "10", "&"])
看起来你并不在乎系统调用的结果,所以我猜你是在做一些离线(或者后台)处理。
我建议你用一种更干净的方法来处理,而不是直接执行一个程序。可以使用像Gearman这样的队列系统,把处理任务放到队列里,然后让一个单独的工作程序去处理这些队列里的任务。
这样做的好处是,当流量突然增加时,可以保护你的服务器,避免每次请求这个视图时都去启动一个新进程。你可以根据需要,慢慢或者快速地处理队列里的任务,跟流量无关。
虽然流量可能不是问题,但我个人觉得这样设计更干净。