如何在Python中运行另一个脚本而无需等待其完成?

42

我正在为用户创建一个小仪表板,允许他运行特定的作业。我使用 Django,所以我希望他能够点击链接启动作业,然后将页面返回给他,并显示消息表示作业正在运行中。作业的结果将在稍后通过电子邮件发送给他。

我认为我应该使用subprocess.Popen,但我不确定。因此,在伪代码中,这是我想要做的:

if job == 1:
    run script in background: /path/to/script.py
    return 'Job is running'

可能是重复的问题,与 在Python中启动后台进程如何在后台启动和运行外部脚本? 相同。 - oHo
4个回答

66
p = subprocess.Popen([sys.executable, '/path/to/script.py'], 
                                    stdout=subprocess.PIPE, 
                                    stderr=subprocess.STDOUT)

那会在后台启动子进程。你的脚本将正常运行。

在这里阅读文档here


nosklo:谢谢。我该如何向脚本传递参数? - sheats
4
作为第一个参数传递的列表中有额外的元素。链接的文档很有用,而且有它的原因。 - Devin Jeanpierre
在非Windows环境下,你可以使用os.fork进行检查。 - Bodo Thiesen
stdout=PIPE 可能会挂起子进程,将其重定向到 DEVNULL 以丢弃输出。 - jfs
@nosklo,我们能否像传递给函数一样,从上一个进程向新的子进程传递一个新参数? - user5319825
显示剩余4条评论

6

如果您考虑到长期扩展,通过消息队列运行是明智的选择。向后台持续运行的队列发送消息,并编写作业处理程序以处理不同类型的消息。

由于您正在使用Django,我认为Beanstalkd是一个相当好的选择。 这里有一个非常好的教程。该文章中的第一条评论也有一些很好的提示。

就我个人而言,我使用了一个自定义的内存队列服务器,用Erlang编写,在C中编写Python绑定。但是,redis看起来可能成为未来排队/消息需求的一个很好的竞争者。希望这可以帮助您!


3
celery(http://pypi.python.org/pypi/celery)也是一个很好的选择。它使用RabbitMQ(用于消息持久化,如果有人有时间,也可以使用beanstalkd后端来支持carrot)。beanstalkd教程只解决了发送消息的问题,但让读者自己练习实际执行任务。 - asksol

2

subprocess.Popen确实是您要寻找的内容。


1

虽然如果你发现你想在子进程和父进程之间开始传递大量信息,你可能需要考虑使用线程或类似Twisted的RPC框架。

但很可能这些对于你的应用程序来说太重了。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接