【问题标题】:Only first subprocess.Popen(..., stdin=f) in a loop works correctly只有循环中的第一个 subprocess.Popen(..., stdin=f) 才能正常工作
【发布时间】:2018-06-14 21:46:48
【问题描述】:

我的主要目标是获取连接 Linux 的计算机列表的所有 cpu 费用。我一直在网上挣扎和搜索一段时间,但我必须错过一些东西,因为我找不到我的答案。 所以我定义了一个 cpu_script.py :

import psutil

print(psutil.cpu_percent(interval=1,percpu=True))

在我的主脚本中调用,该脚本位于同一文件夹中,带有:

import subprocess
import os
import numpy as np
import psutil

usr = "AA"
computer = ["c1", "c2", "c3"] #list of computer which cpu load is to be tested
cpu_script = os.path.join(os.getcwd(),"cpu_script.py")

with open(cpu_script,"rb") as f:
    for c in computer:
        input(c)
        process = subprocess.Popen(["ssh","-X",usr + "@" + c,"python3","-u","-"], stdin=f, stdout=subprocess.PIPE)
        out = process.communicate()[0]
        input(out)

现在这是我从这些input 中得到的:

>> c1 #first computer
>> <subprocess.Popen object at 0x7fd210aab358>
>> b'[1.0, 7.1, 0.0, 1.0, 2.0, 2.0, 3.0, 0.0, 0.0, 0.0, 0.0, 1.0]\n'
>> c2 #second computer
>> <subprocess.Popen object at 0x7fd210aab390>
>> b''
>> c3 #third computer
>> <subprocess.Popen object at 0x7fd210aab390>
>> b''

所以这是我的问题:为什么第二个和第三个输出是空的?我怎么能得到它们?

我怀疑我的第一个进程没有很好地“关闭”,所以我尝试在input(out) 之后添加process.wait()process.kill(),但无济于事。

提前感谢您的帮助!


编辑:subprocess.check_output() 提供相同的输出。我还尝试了subprocess.run

with open(cpu_script,"rb") as f:
    for c in computer:
        input(c)
        process = subprocess.run(["ssh","-X",usr + "@" + c,"python3","-u","-"], stdin=f, stdout=subprocess.PIPE)
        input(out)

得到:

>> c1 #first computer
>> CompletedProcess(args=['ssh', '-X', 'usr@c1', 'python3', '-u', '-'], returncode=0, stdout=b'[2.0, 1.0, 1.0, 2.9, 7.0, 0.0, 2.0, 1.0, 0.0, 0.0, 0.0, 1.0]\n')
>> c2 #second computer
>> CompletedProcess(args=['ssh', '-X', 'usr@c2', 'python3', '-u', '-'], returncode=0, stdout=b'')
>> c3 #third computer
>> CompletedProcess(args=['ssh', '-X', 'usr@c3', 'python3', '-u', '-'], returncode=0, stdout=b'')

【问题讨论】:

  • 如果您对Popen 对象所做的一切都是为了获取输出,为什么不直接使用subprocess.check_output()(或者,如果您有Python 3.5+,则使用subprocess.run())来代替?跨度>
  • 您的评论很相关,我一开始就选择了subprocess.check_output(),但我遇到了同样的问题。我发现也许使用 Popen 我可以在之后讨厌地终止该进程,希望能解决问题(但它没有)......
  • 对于run,我有同样的问题,但我会编辑我的问题以正确显示输出
  • 仅供参考,当您传递 ssh 一堆以空格分隔的参数(如在 "python3", "-u", "-" 中)时,它只是将它们与空格连接起来并将结果作为单个字符串传递给由远程外壳。这是完全危险的,因为您可能认为对于任意代码来说是安全的,但通常情况并非如此; ['echo', unknown_string] 是安全的,f/e,但如果你的 unknown_string 包含 $(rm -rf ~)'$(rm -rf ~)'['ssh', 'somehost', 'echo', unknown_string] 会给你带来痛苦。考虑['ssh', 'host', ' '.join([pipes.quote(x) for x in ['echo', unknown_string]])],一种更安全的模式
  • 感谢您的评论 Charles Duffy,当我的输出问题解决后,我会寻找此增强功能:)

标签: python python-3.x subprocess psutil


【解决方案1】:

这里的问题是,一旦你的文件被读取了一次,指针就在文件的末尾,所以没有什么可以读取(所以第二次你通过stdin=f 为同一个文件,剩下的是只是空的)。

每次你想使用它时,反转你的内循环和外循环一次重新打开文件:

for c in computer:
    with open(cpu_script, "rb") as f:
        process = subprocess.Popen(["ssh", "-X", "-l", usr, c, "python3 -u -"],
                                   stdin=f, stdout=subprocess.PIPE)
        out = process.communicate()[0]

...或使用seek() 函数倒回到内部循环之间的开头:

with open(cpu_script, "rb") as f:
    for c in computer:
        f.seek(0)   ### <- THIS RIGHT HERE
        process = subprocess.Popen(["ssh", "-X", "-l", usr, c, "python3 -u -"],
                                   stdin=f, stdout=subprocess.PIPE)
        out = process.communicate()[0]

【讨论】:

  • 感谢您的回答和解释!我已经尝试反转循环(当你绝望时,你知道!)但我得到这个奇怪的错误:对于 c1,它工作正常,对于 c2 我得到这个错误&lt;subprocess.Popen object at 0x7ff90913e128&gt;Traceback (most recent call last): File "&lt;stdin&gt;", line 1, in &lt;module&gt; ImportError: No module named 'psutil',我的输出是b''。但是,对于 c3,我得到了正确的输出。我尝试添加一个process.wait(),但它并没有解决第二次通话问题
  • 我也遇到了与 f.seek(0) 相同的问题
  • 所以你需要在你的远程机器上安装 psutil 模块。这是您使用的整个方法(通过网络发送 Python 代码)的一个先天问题——您的远程系统必须安装代码使用的模块。
  • ...也就是说,我不太清楚您为什么要使用 psutil ——您只是想要平均负载吗?为什么不让你的命令["ssh", "-l", usr, c, "cat /proc/loadavg"] 直接从内核收集它,并且根本不需要在远程机器上使用/需要 Python 解释器,因此也不需要你的 cpu_script 文件? (也没有理由拥有-X,因为您所做的任何事情都不需要 X11 转发)。
猜你喜欢
  • 2013-05-30
  • 2016-11-14
  • 2014-11-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-03
  • 2021-03-01
  • 1970-01-01
相关资源
最近更新 更多