无法让python subprocess.Popen()在后台启动另一个python脚本

0 人关注

我在这里遇到了一些麻烦。我有一个python脚本(gather.py),它从一个.xml文件中收集信息,并在一个无限循环中上传至数据库,睡眠时间为60秒;另外,这些都是本地的。我正在使用Flask来运行一个网页,该网页随后将从数据库中获取信息,但目前它所做的只是显示一个样本页面(main.py)。我想运行main.py,让它把gather.py作为后台进程启动,这样就不会妨碍Flask的启动,我试着导入gather.py,但是它停止了进程(无限期),Flask也不会启动。在谷歌搜索了一段时间后,似乎最好的选择是使用一个任务队列(Celery)和一个消息中介(RabbitMQ)来处理这个问题。如果应用程序要在后台做很多事情,这很好,但我只需要它做1或2件事情。所以我做了更多的调查,发现有帖子说 subprocess.Popen() 可以做这个工作。我试着使用它,我认为它没有失败,因为它没有引发任何错误,但数据库是空的。我确认gather.py和main.py都能独立工作。我试着在IDLE中运行下面的代码。

subprocess.Popen([sys.executable, 'path\to\gather.py'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT)

并得到这样的回报。

<subprocess.Popen object at 0x049A1CF0>

现在,我不知道这意味着什么,我试着用 .value .attrib ,但可以理解的是我得到了这个。

AttributeError: 'Popen' object has no attribute 'value' AttributeError: 'Popen' object has no attribute 'attrib'

然后我在StackOverflow的帖子上看到, stdout=subprocess.PIPE 会导致程序停止,所以,在 "以防万一 "的时刻,我运行了。

subprocess.Popen([sys.executable, 'path\to\gather.py'], stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)

并得到这样的回报。

<subprocess.Popen object at 0x034A77D0>

在所有这些过程中,数据库表一直是空的。我是 subprocess 模块的新手,但所有这些检查,我都搞不清楚为什么它不能运行gather.py。是不是因为它有一个无限的循环?如果有更好的选择,请告诉我。

Python version: 3.4.4

PS.不知道这是否重要,但我在Windows 10 PC上运行的是Python的便携版本(PortableApps)。这就是为什么我把 sys.executable 包含在 subprocess.Popen() 里面。

5 个评论
欢迎来到Stackoverflow。你可能想在你的问题中添加一些关于你使用的平台(Linux、Windows)的信息
你是否打印了 "sys.executable "的结果以查看变量中的内容?如果 python 无法得到路径,sys.executable 将返回 None 或空字符串。
André Ginklings,我确实打印了 sys.executable 的值,它指向了python。下面是输出结果。 【替换代码0 【替换代码2
如果你打开一个命令提示符(cmd.exe)并执行 G:\PortableApps\WinPythonPortable\App\WinPython\python-3.4.4\python.exe path\to\gather.py ,脚本就能工作?
安德烈-金克林斯,是的。
python
python-3.x
subprocess
Rex-Raiden-X
Rex-Raiden-X
发布于 2020-11-26
2 个回答
André Ginklings
André Ginklings
发布于 2020-11-27
已采纳
0 人赞同

解决方案1(全部在python脚本中)。 尝试使用线程和队列。

I do this:

from flask import Flask
from flask import request
import json
from Queue import Queue
from threading import Thread
import time
def task(q):
    q.put(0)
    t = time.time()
    while True:
        time.sleep(1)
        q.put(time.time() - t)
queue = Queue()
worker = Thread(target=task, args=(queue,))
worker.start()
app = Flask(__name__)
@app.route('/')
def message_from_queue():
    msg = "Running: calculate %f seconds" % queue.get()
    return msg
if __name__ == '__main__':
    app.run(host='0.0.0.0')

如果你运行这段代码,每次访问'/'都会在后台的task中得到一个计算值。也许你需要阻塞,直到任务得到一个值,但问题中的信息并不充分。当然,你需要重构你的gather.py,为它传递一个队列。

解决方案2(使用系统脚本)。

对于windows系统,创建一个.bat文件并从那里运行这两个脚本。

@echo off
start python 'path\to\gather.py'
set FLASK_APP=app.py
flask run

这将运行gather.py并在启动flask服务器之后。如果你使用start /min python 'path\to\gather.py',gather将以最小化模式运行。

André Ginklings,谢谢你的回答。我确实想到了线程,但无法让它发挥作用。肯定是因为我没有使用 Queue 模块。无论怎样,我都放弃了,因为我需要gather.py在后台独立于main.py运行。当我把这个应用程序投入生产时,gather.py应该持续运行。我想看看我是否可以从python中启动它,然后添加一个函数来检查它是否在运行,如果没有的话就运行它。BTW,我应该在帖子中添加什么额外的信息?
你想用 gather.py 做什么?这是一个后台进程,OK。但这是什么时候运行的?只有当Flask应用也在运行时?还是一直在运行?如果你需要在flask应用的main.py中运行这个,Popen应该也能工作,Thread也是。如果你需要gatter.py作为一个服务来执行,不管Flask应用是否在运行,你只需要把它作为系统服务来执行(这样你就可以知道你的系统是什么)。如果你从终端手动运行gather.py并运行Flask应用,它能如你所愿吗?
André Ginklings 我想通过一次调用来启动这两个程序。它[gather.py]应该一直在运行,但在停电的情况下,我希望能够只运行一个脚本,然后一切就都结束了。我只想运行一个文件,而不是两个独立的文件,我使用的是Windows 10。这个应用程序将被放入生产的服务器也是一个Windows环境。我知道我可以使用像NSSM这样的东西将gather.py作为一个服务来运行,但这将使它依赖于操作系统,我希望能避免这一点。
我使用一个windows的批处理脚本来更新我的问题。
POINT ONE
POINT ONE
发布于 2020-11-27
0 人赞同