【问题标题】:subprocess blocks Django view子进程阻止 Django 视图
【发布时间】:2011-06-19 07:16:13
【问题描述】:

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

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

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

已经有a few questions on that topic,Google 给出了a few other threads,但我找不到我的问题的明确答案。

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

python -c '导入子进程; print 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

    导入子流程

    定义你好(请求):
    返回 HttpResponse('Hello world!')

    定义开始(请求):
    subprocess.Popen(["/bin/sleep", "10"])
    return HttpResponse('开始完成')

测试一下:

./manage.py 运行服务器 0.0.0.0:8000

转到http://127.0.0.1:8000/hellohttp://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) - « 开始 » 已保存 [10]

【问题讨论】:

    标签: python django subprocess


    【解决方案1】:

    试试这个

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

    【讨论】:

    • 这无济于事:它会阻塞服务器 10 秒。
    【解决方案2】:

    我在使用 nginx+uwsgi 运行 Django 时遇到了同样的问题。通常断点是 web-server 的模块,在我的例子中是 uwsgi。添加&lt;close-on-exec/&gt; 解决了这个问题。另一方面,fastcgi 模块不会导致查看挂起在后台进程上。

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

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

    【讨论】:

    • 特别是命令帮助,仍然想知道为什么会出现问题
    【解决方案3】:

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

    我会建议一种更简洁的方法,而不是直接执行程序。使用诸如Gearman 之类的排队系统将处理任务排队,然后有一个单独的工作人员从队列中消费项目。

    这具有在发生大流量高峰时保护您的服务器的优势,因此您不会在每次向该视图发出请求时分叉一个进程。您可以根据自己的决定以慢或快的速度消费项目,而不受流量的影响。

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

    【讨论】:

    • 感谢您的回答。是的,它是后台处理。预期流量低(小型 Intranet)。我同意排队系统会更清洁,但客户还没有准备好......
    • 如果必须生成进程,则需要使用管道重定向输出。请参阅stackoverflow.com/questions/546017/… 以获得合理的答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-11
    • 1970-01-01
    • 2011-03-17
    • 2011-08-19
    • 1970-01-01
    • 2016-03-22
    • 1970-01-01
    相关资源
    最近更新 更多