当从 Django 内部调用时,Subprocess.Popen 与交互式程序一起挂起

Posted

技术标签:

【中文标题】当从 Django 内部调用时,Subprocess.Popen 与交互式程序一起挂起【英文标题】:Subprocess.Popen hangs with interactive programs when called from inside Django 【发布时间】:2011-03-26 06:22:40 【问题描述】:

我编写了一个小型 Django 应用程序,它根据用户输入执行交互式程序,并将输出作为结果返回。但由于某种原因,子进程挂起。在验证日志时,我发现必须给出“\n”作为对挑战的响应的地方,似乎从未做出响应。有趣的是,如果我从 Django 外部运行相同的代码,即从 python 模块或交互式 shell,子进程可以顺利运行。我假设 Django 使用的环境中的一些设置是这里的罪魁祸首。以下是我编写的代码的 sn-ps:

def runtests(test_name, selective=False, tests_file=''):
    if selective:
        run_cmd = ['runtest', '--runfromfile', tests_file, test_name]
    else:
        run_cmd = 'runtest %s' % (test_name)
    print 'Executing command .. '
    print run_cmd
    p = subprocess.Popen(run_cmd, shell=False, stdout=subprocess.PIPE,
                        stderr=subprocess.STDOUT)

    return p.stdout.read()

def result(request):
    test_name = request.GET['test_name']
    if not test_name:
        return render_to_response('webrun/execute.html', 'error_flag':True)

    in_file = os.path.abspath('webrun/log/%s_in.xml' % test_name)
    suites = dict([(field[len('suite_'):],value) 
                            for field,value in request.GET.items() 
                            if field.startswith('suite_')])
    if suites:
        _from_dict_to_xml(suites, in_file, test_name)
    output = runtests(test_name, bool(suites), in_file)

    return render_to_response('webrun/result.html', 'output':output)

我尝试用旧的 os.system 方法替换子进程。但即便如此,它也挂在完全相同的地方。同样,如果我从 Django 中执行相同的代码,这也会运行。

【问题讨论】:

互动是什么意思?子处理的运行测试程序是否需要在其标准输入上输入?我只看到您使用一些命令行参数运行它。 你是如何运行 django 的? runserver? modpython? wsgi? @Mark 感谢您的回复。我想我对交互式的使用并不正确。实际上,runtest 程序与网络中的设备打开一个 shell,并通过响应设备给出的提示进行交互。用户本身没有交互。 @MattH 感谢您的回复。我目前正在使用 Django 附带的开发服务器。 【参考方案1】:

我的问题在于我在 Pycharm 中运行 Django。运行./manage.py runserver 直接为我修好了。

【讨论】:

【参考方案2】:

我认为您的问题是“runtest”程序所在的目录。您的视图将在视图所在的同一目录中获取该模块。如果模块位于其他任何位置,您还可以在 Popen 参数列表中指定“cwd”参数。 我在 Django 开发服务器的视图中使用 Popen 命令没有任何问题,因此开发服务器不是您问题的原因。

【讨论】:

感谢您的回复。我已经尝试过 cwd,但它仍然不能解决我的问题。【参考方案3】:

我在做这种事情来获得善变的小费版本时遇到了同样的问题:

import subprocess

lProcess = subprocess.Popen(["hg","tip"], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
lOutput = lProcess.stdout.readline()
lTipRevision = lOutput[10:].strip()
lTipRevision = lTipRevision[:lTipRevision.find(":")].strip()
print "Repository tip version is %s" % lTipRevision

这在通过 apache (mod_wsgi) 运行时可以正常工作,但会导致开发服务器中出现空白页。

我在与此相关的错误周围徘徊,我能找到的错误似乎已作为重复或已关闭的工作表关闭。

http://code.djangoproject.com/ticket/9286 http://code.djangoproject.com/ticket/4953 http://code.djangoproject.com/ticket/3712

我关于这个的原始帖子可以在http://groups.google.com/group/django-users/browse_thread/thread/147ffe75899fd6e?pli=1找到

【讨论】:

我可能应该转移到 apache 并尝试这个。似乎我遇到了 Django 开发服务器的相关错误。谢谢。【参考方案4】:

subprocess documentation 建议您“使用通信()而不是 .stdin.write、.stdout.read 或 .stderr.read 以避免由于任何其他操作系统管道缓冲区填满并阻塞子进程而导致的死锁。”

如果你使用return p.communicate()[0]而不是return p.stdout.read(),它会起作用吗?

【讨论】:

我已经尝试过通信()[0]。但没有运气。不过感谢您的回复。

以上是关于当从 Django 内部调用时,Subprocess.Popen 与交互式程序一起挂起的主要内容,如果未能解决你的问题,请参考以下文章

当从 UIActivityViewController 调用时,WhatsApp 在选择收件人后冻结

当从其他操作调用操作时,@Check 不起作用

当从同一个组件调用时,两个 IBAction 触发的顺序是啥?

文件的间接路径,当从其他地方调用程序时

当从不同的类调用更改时,UIView IBOutlet 不会更改

当从一个子调用但另一个子调用时添加控件的子工作