【问题标题】:Corrupt file for stdout in python subprocesspython子进程中标准输出的损坏文件
【发布时间】:2014-04-26 11:10:42
【问题描述】:

我想编写一个 python 脚本,该脚本从作业列表中运行多个 c++ 程序。

我认为它工作正常,但我的输出文件有问题,它似乎已损坏或其他什么。反正我打不开。也许你们可以帮助我。

import multiprocessing
import psutil
import subprocess
import time

jobs2Do = True

while (jobs2Do):    #Ever-running program

cpuLoad = cpuLoad + psutil.cpu_percent()

if (cpuLoad < 90):
    with open('JobQueue.txt', 'r') as f:
        first_line = f.readline()
        path = f.readline()
        f.close()
    if (first_line != ""):
        print "Opening " + first_line
        process = subprocess.Popen( first_line, shell=True, stdout=open(path,"w"),stderr=open("error.log","w"))

        with open('JobQueue.txt', 'r') as fin:
            data = fin.read().splitlines(True)
        with open('JobQueue.txt', 'w') as fout:
            fout.writelines(data[2:])
        with open("JobsDone.txt", "a") as myfile:
            myfile.write(first_line)
            myfile.write(path)
        myfile.close()

    else:
        print "No more jobs... waiting for new jobs...."
        time.sleep(10)

好的,所以我(想要)做的是:我检查 cpu 是否有一些空闲容量,如果有,打开带有作业的文件并获取命令,该命令位于该文件的第一行,以及程序的所有输出应保存到的路径。这总是在文件的第二行。

然后我想打开那个子进程,把标准输出放到我的首选路径,然后把错误流放到任何地方。最后,我从列表中删除作业并从头开始。

我现在的问题是,stdout=open(path,"w") 似乎有点损坏,因为我无法访问甚至删除它,但我可以在文件夹中看到它。

也许你们有一个想法,我做错了什么。

感谢您的努力!

NonStopAggroPop

PS:也许我还应该补充一点,c++ 程序运行时间更长。所以我有意要做的就是让程序执行 nohup ./c++ [arguments] 并将输出流式传输到特定文件,就像我在控制台中键入它一样。

PPS:我希望能够在其他程序仍在运行时启动多个 c++ 程序,直到我的 cpu 达到 100% 使用率。

【问题讨论】:

  • 当然可以去掉c++标签?
  • 是的,你是对的,标签被建议了,但主要是它的一个 python 问题。对不起!
  • 也许子流程还在工作?尝试将process.communicate() 放在process = subprocess.Popen(... 行之后。它将等待子进程终止。
  • 你不必关闭文件,如果你用 with 打开它们。您无需等待该过程,这可能会带来一些释放资源的问题,例如关闭文件。
  • 你在哪里填写 JobQueue?在没有前两行的情况下读取整个文件和回写之间存在竞争条件。

标签: python subprocess stdout


【解决方案1】:

我现在的问题是,stdout=open(path,"w") 似乎有点损坏,因为我无法访问甚至删除它,但我可以在文件夹中看到它。

问题是path = f.readline() 返回一个结尾带有 换行符 的字符串。 open(path, 'w') 在某些系统上并不关心,并在最后创建带有换行符的文件。尝试print(os.listdir('.')) 以查看文件名中的\n

要修复它,只需删除换行符:path = path.strip()


您的代码中还有其他不相关的问题:

  • 您正在混合使用制表符和空格进行缩进。永远不要那样做:它使视觉缩进与 Python 看到的不同,因为它目前在你的问题中。要么总是使用制表符或空格,而不是两者。您可以将编辑器配置为在按 Tab 键时插入 4 个空格。

  • 您的意思可能是 cpuLoad = psutil.cpu_percent() 而不是 cpuLoad = cpuLoad + psutil.cpu_percent(),这会无缘无故地增加循环的每次迭代

  • 从命令中删除换行符并删除shell=True。除非必要,否则不要使用 shell(这是一个好习惯,如果你知道自己在做什么,有时可能会被打破):

    import shlex
    
    process = Popen(shlex.split(command),
                    stdout=output_file, stderr=stderr_file)
    
  • 使用with-statements 使代码与其他 Python 实现(例如 Jython、Pypy)兼容:

    with open(path, 'w') as output_file:
         with open('error.log', 'w') as stderr_file:
             process = Popen(shlex.split(command),
                             stdout=output_file, stderr=stderr_file)
    

    否则文件可能会在父进程中保持打开状态。

  • 在关闭 文件本身,即使发生异常是它的目的,它的 存在的理由。 .close() 是无害的,但在这方面毫无意义 案例

  • 使用if not first_line.strip():测试第一行是否为空白(仅包含空格)

  • 手动编辑JobQueue.txt 的整个想法是脆弱的。没有什么能阻止 Python 进程只读取部分输入。您可以使用专用命令添加新作业,例如at-like 实用程序。并根据您的喜好实现它,例如,在端口上侦听主脚本中的新作业并在at-like 实用程序中发送作业。这是the very basic socket client and server in Python 的代码示例。或者使用其他 IPC 方法。

【讨论】:

  • 就是这样!真的很感激!对于您的第二个要点:我取 cpuLoad 的平均值,因此我将值累积 5 次,在两者之间稍等片刻,然后将其除以 5。我将其从示例代码中删除以使其更多可读。不过有一点:如果我删除“shell = True”,它就不起作用。我收到错误消息:在 execute_child 的 subprocess.py 中引发子异常“没有这样的文件或目录”。但是使用 shell=True 它可以像我想要的那样运行。真的(!!!)感谢您的帮助!祝先生周日愉快!
  • @NonStopAggroPop:如果你想要一个平均值;查看interval参数的描述psutil.cpu_percent。除非您想在 bash 中运行诸如 help 之类的内置 shell 命令,或者您想创建管道,例如 a | b,否则您不需要 shell=True。使用 shell 运行可能会产生不良副作用,例如,它可能会改变 process.kill() 的工作方式。尝试指定命令的完整路径。查看print(shlex.split(command)) 并确保它具有预期值
猜你喜欢
  • 2011-08-29
  • 1970-01-01
  • 1970-01-01
  • 2013-02-16
  • 1970-01-01
  • 2010-11-19
  • 2016-12-01
  • 2015-01-20
  • 2020-07-05
相关资源
最近更新 更多