在 django 视图中使用 subprocess.Popen() 执行 python 脚本

Posted

技术标签:

【中文标题】在 django 视图中使用 subprocess.Popen() 执行 python 脚本【英文标题】:Executing a python script using subprocess.Popen() in a django view 【发布时间】:2011-03-09 19:40:34 【问题描述】:

我环顾四周,但似乎无法解决我遇到的这个问题。我想在我的 django 应用程序的视图中执行一个 python 脚本。我已将要执行的代码放在 django 管理命令中,以便可以通过命令行python manage.py command-name 访问它。然后我尝试使用subprocess.Popen("python manage.py command-name",shell=True) 运行此命令。

但是,此命令可能需要一些时间才能执行,因此我希望视图继续并允许脚本在后台执行。单独使用 subprocess.Popen 似乎会导致视图挂起,直到脚本完成,所以我尝试使用线程(遵循another SA 问题):

class SubprocessThread(threading.Thread):
def __init__(self, c):
    self.command = c
    self.stdout = None
    self.stderr = None
    threading.Thread.__init__(self)

def run(self):
    p = subprocess.Popen(self.command,
                         shell=True,
                         stdout=subprocess.PIPE,
                         stderr=subprocess.PIPE)

    self.stdout, self.stderr = p.communicate()

然后执行它:

t = SubprocessThread("python manage.py command-name")
t.setDaemon(True)
t.start()
t.join()

但是,视图仍然挂起:光标有一个忙碌的符号,并且页面上的 AJAX 没有加载。否则,页面的 html 似乎可以正常加载,并且线程调用后视图中的命令似乎正常完成(在脚本完成之前)。有人可以帮帮我吗?我希望脚本能够执行并做自己的事情,而无需阻止页面上的视图或 AJAX 调用。

【问题讨论】:

我经常使用类似的模式(使用subprocess,因为在视图函数退出时会杀死thread),并且我经常忘记在视图函数中返回某些内容,从而使浏览器悬挂。然后,我责怪子进程,而我只是忘记返回HttpResponse。检查一下! 【参考方案1】:

也许你应该使用celery

Celery 是一个基于任务队列/作业队列的 关于分布式消息传递。它是 专注于实时操作

【讨论】:

【参考方案2】:

我浪费了很多时间来尝试实现类似的东西,但遇到了和你一样的问题。最终,我放弃并实现了一个 beanstalk 队列来处理这项工作。

http://kr.github.com/beanstalkd/

我在 Django 视图中的队列上放了一个 id,然后有一个管理命令来运行消费者(由 supervisord 监视)。

使用队列意味着您可以扩展到多个消费者,并允许更好地管理负载(必要时暂停消费者而不会丢失所需的工作)。

【讨论】:

以上是关于在 django 视图中使用 subprocess.Popen() 执行 python 脚本的主要内容,如果未能解决你的问题,请参考以下文章

Py3.5 subprocess.run 意外的 kwarg 'stderr'

OSError:[Errno 2]在Django中使用python子进程时没有这样的文件或目录

在 django 中使用 celery 和 ffmpeg 对视频进行转码

如何在django视图函数中使用全局变量,对所有线程有效。

Django中的RESTful api在Django中使用inbult视图,无需创建2个url

在 django 中使用物化视图或替代方案