为什么在Django视图中使用Popen会挂起?
在我的一个Django视图中,我需要启动一个异步任务,这个任务可能需要几分钟才能完成。因为使用Celery加消息队列对这个任务来说有点过于复杂,所以我用了subprocess.Popen来创建一个子进程,像这样:
args = ['python', SCRIPT_PATH, "&"];
try:
subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) # Async call
except:
pass
return HttpResponse("Job submitted")
我用nginx和gunicorn来运行我的Django应用。当我启动服务器并保持命令行会话打开时,上面的代码运行得很好。但是当我关闭命令行会话时,代码就停止工作,并且在Popen那一行卡住了。
我猜这和stdout(标准输出)和stderr(标准错误)参数有关,但我不知道该怎么改才能让它正常工作。
=========编辑===========
在我的脚本中,我使用了selenium webdriver和phantomjs来加载一个网页并提交一个表单。在这个过程中,selenium或phantomjs会向标准输出或标准错误写入信息。当我在命令行中启动gunicorn,然后关闭命令行会话时,selenium或phantomjs的写入就失败了。当我用下面这种方式启动gunicorn,并把输出重定向到一个文件时:
gunicorn app.wsgi > /tmp/gunicorn.log &
问题就解决了。
1 个回答
3
虽然我不能确定你提到的Popen那一行为什么会阻塞,但我可以给你一个替代方案。另外,我也不太确定你是否需要使用"&"这个选项。
你可以像这样使用NamedTemporaryFiles来处理标准输出和错误输出流:
from tempfile import NamedTemporaryFile
output = NamedTemporaryFile(delete=False)
error = NamedTemporaryFile(delete=False)
Popen(args, stdout=output, stderr=error)
这样做不会造成阻塞。我想你应该已经处理好了Popen完成后要做的事情。
Popen的文档中有关于PIPE对象的警告。我把它贴在这里以便完整:
读取的数据会缓存在内存中,所以如果数据量很大或者没有限制,就不要使用这种方法。