Python子进程中的stdout文件损坏

1 投票
1 回答
928 浏览
提问于 2025-04-18 04:21

我想写一个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)保存到我指定的路径,把错误信息(errorstream)放到其他地方。最后,我会把这个任务从列表中删除,然后重新开始。

现在我的问题是,stdout=open(path,"w")似乎有点问题,因为我无法访问或删除这个文件,但我在文件夹里能看到它。

也许你们能想出我哪里做错了。

谢谢你们的帮助!

NonStopAggroPop

PS:我还想补充一下,这些C++程序运行的时间比较长。所以我本来想做的是让程序执行nohup ./c++ [参数],并把输出流到一个特定的文件,就像我在控制台输入一样。

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

1 个回答

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 语句,使代码与其他 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)
    

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

  • with 语句后,去掉 f.close()myfile.close(),因为 with 语句会自动关闭文件,即使发生异常也是如此,这是它的目的。虽然 .close() 是无害的,但在这种情况下是多余的。

  • 使用 if not first_line.strip(): 来检查第一行是否为空(只包含空白字符)。

  • 手动编辑 JobQueue.txt 的想法很脆弱。没有什么能阻止 Python 进程只读取部分输入。你可以使用专门的命令来添加新任务,比如类似 at 的工具。你可以根据自己的想法实现,比如在主脚本中监听一个端口以接收新任务,并将任务发送到类似 at 的工具。这里有一个关于 Python 中非常基础的套接字客户端和服务器的代码示例。或者使用其他进程间通信的方法。

撰写回答