有没有简单的方法可以在Python CGI脚本中启动一个后台任务而不必等待它终止?
在Windows系统上,这个问题的答案是我需要创建一个Windows服务。不过,这听起来对我想做的事情来说有点太复杂了。
我只是想给我的经理做一个小原型,我并不打算把它变成正式产品……实际上,它可能根本不会被做成产品;可能只是一些研究人员用来玩玩的东西。
我有一个CGI脚本,它接收一个文件上传,先把文件存到临时位置,然后启动一个后台进程来对文件进行一些复杂的计算。接着,一些JavaScript代码会调用其他CGI脚本来检查状态,并根据需要更新页面。
这一切都能正常工作,除了那个该死的web服务器在子进程运行时不会关闭连接。我查了一下,发现Unix上的解决办法是把它做成一个守护进程,但我现在在Windows上,我想那里的解决办法就是做成一个Windows服务?!这听起来实在是太复杂了,只是想启动一个进程,然后关闭服务器连接。
这真的是唯一的办法吗?
编辑:好吧,我在这里找到一个不错的小技巧(那个家伙给的选择(3)): 如何在IIS下的Perl CGI中完全后台运行一个进程
我能够对这个方法进行修改,让它变得更简单,虽然这个解决方案有点笨拙,但对于我想做的快速原型来说非常合适。
所以我最开始的主脚本是这样做的:
subprocess.Popen("python.exe","myscript.py","arg1","arg2")
但这并不奏效,正如我所描述的。现在,我的主脚本发出这段JavaScript代码,它会在文档完全加载后运行:
$("#somecrap").load("launchBackgroundProcess.py", {arg1:"foo",arg2:"bar"});
然后launchBackgroundProcess.py负责执行subprocess.Popen。
这个解决方案永远无法扩展,因为在后台任务运行期间,浏览器连接仍然保持打开状态。但由于我正在制作的这个小东西可能将来最多只有两个同时用户(即使那样我也不太相信),所以资源不是问题。这允许用户看到主页面,并在后台任务运行时接收JavaScript更新,即使有一个HTTP连接无缘无故地保持打开。
谢谢大家的回答!如果我将来被要求将这个做成产品,我会参考Profane推荐的资源。
4 个回答
最简单的方法,但不是最有效的方式,就是直接运行另一个 Python 程序。
from subprocess import Popen
Popen("python somescript.py")
你可以使用一个叫做 system
的命令,配合 "start" 这个 Windows 命令来实现。这样,你的 Python 脚本就不会等着刚启动的程序完成后再继续执行。
如果你对Windows编程不太熟悉,又不想去看那些复杂的MSDN文档——我完全理解——那么你可以试着找一本Mark Hammond写的关于Python和Windows的经典指南。这本书在很多常见问题上总是能提供帮助,几乎不会过时。与其用一种适合所有平台的方法来启动进程,你可能更好地使用win32process模块。Hammond书的第17章对此进行了详细讲解,不过你也可以通过下载pywin IDE来获取所需的内容(我记得它是和Windows扩展一起提供的,你可以从pypi下载),然后查看它关于Python Windows API的帮助文档。下面是我最近在一个项目中使用API的一个例子。经过一些调整,它可能正好能满足你的需求。你可能需要关注CreationFlags,特别是win32process.DETACHED_PROCESS,它“通常用于在后台执行控制台程序。”还有许多其他的标志可供使用,并且它们都很方便。
if subprocess.mswindows:
su=subprocess.STARTUPINFO()
su.dwFlags |= subprocess._subprocess.STARTF_USESHOWWINDOW
process = subprocess.Popen(['program', 'flag', 'flag2'], bufsize=-1,
stdout=subprocess.PIPE, startupinfo=su)