在Django内调用时,Subprocess.Popen与交互式程序挂起
我写了一个小的Django应用,它根据用户的输入执行一个互动程序,并把结果返回给用户。但是不知道为什么,子进程总是卡住。在查看日志时,我发现有一个地方需要给出一个'\n'作为对某个挑战的回应,但这个回应似乎从来没有发出。有趣的是,如果我在Django之外运行相同的代码,比如在一个Python模块里或者在交互式命令行中,子进程就能正常工作。我猜可能是Django使用的环境设置出了问题。以下是我写的代码片段:
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之外执行相同的代码,它又能正常运行。
4 个回答
我觉得你的问题可能出在'runtest'程序所在的文件夹上。你现在的视图会在它自己所在的文件夹里寻找这个模块。如果这个模块在其他地方,你可以在Popen的参数列表中指定'cwd'这个参数来告诉它去哪里找。
我在使用Django开发服务器的视图中用Popen命令没有遇到任何问题,所以开发服务器不是你问题的原因。
subprocess文档建议你使用“communicate()”这个方法,而不是直接用.stdin.write、.stdout.read或.stderr.read,因为这样可以避免因为操作系统的管道缓冲区满了而导致的死锁问题,这种情况会阻塞子进程的运行。
如果你用return p.communicate()[0]
来替代return p.stdout.read()
,这样做有效吗?
我在做类似的事情时也遇到过同样的问题,想要获取mercurial的最新版本:
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)运行时,这个方法很好用,但在开发服务器上却出现了空白页面。
我查了一下与这个问题相关的bug,发现大部分都被标记为重复问题,或者已经关闭,显示“对我来说没问题”。
- 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