我努力寻找并行运行多个OS命令的最佳方法,并能够捕获它们的输出。 OS命令是用C编写的半长期运行的专有实用程序。(在solaris / linux主机上运行并使用python 2.4)从高级别开始,此脚本将从作业队列中提取作业,为每个作业实例化一个类,其中然后,该类使用提供的参数生成OS实用程序。这个类实际上会有更多,但只关注脚本的整体架构,在这种情况下省略的代码是微不足道的。
实际上有两点需要来自此OS命令的输出。
首次执行命令时,它返回一个我需要捕获的jobid。然后该命令将阻塞直到完成。然后我需要捕获此命令的返回码。
我真正想做的(我认为)是定义一个产生线程然后执行Popen()的类。
以下是我现在所拥有的:
#!/usr/bin/python
import sys, subprocess, threading
cmd = "/path/to/utility -x arg1 -y arg2"
class Command(object):
def __init__(self, cmd):
self.cmd = cmd
self.process = None
self.returncode = None
self.jobid = None
def __call__(self):
print "Starting job..."
self.process = subprocess.Popen(self.cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
out, err = self.process.communicate()
self.jobid = out.split()[10]
def alive(self):
if self.process.poll():
return True
else:
return False
def getJobID(self):
return self.jobid
job = Command(cmd)
jobt = threading.Thread(target=job, args=[])
jobt.start()
# if job.alive():
# print "Job is still alive."
# do something
# else:
# print "Job is not alive."
# do something else
sys.exit(0)
这里的问题是使用p.communicate()会导致整个线程被阻塞,而我无法在我想要的位置获得jobid。
此外,如果我取消注释if语句,它会抱怨没有方法alive()。
我已经尝试了各种变体,比如在类的调用方法中创建线程,但这似乎是我走错了路。
我还尝试在生成线程时将类名指定为目标参数:
jobt = threading.Thread(target=Command, args=[cmd])
jobt.start()
我使用过的每一种方法都让我遇到了障碍。
任何建议都是如此。
所以在尝试了dano的想法后,我现在有了这个:
class Command(threading.Thread):
def __init__(self, cmd):
super(Command, self).__init__()
self.cmd = cmd
self.process = None
self.returncode = None
self.jobid = None
def run(self):
print "Starting job..."
self.process = subprocess.Popen(self.cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=0, shell=False)
print "Getting job id..."
out = self.process.stdout.readline()
print "out=" + out
self.returncode = self.process.wait()
def alive(self):
if self.process.poll():
return True
else:
return False
def getJobID(self):
return self.jobid
job = Command(cmd)
job.start()
产生以下输出:
Starting job...
Getting job id...
此时它会挂起,直到OS命令完成。
以下是手动运行此命令的示例。前两行输出立即返回。
$ /path/to/my/command -x arg1 -y arg2
Info: job request 1 (somestring) submitted; job id is 729.
Info: waiting for job completion
# here is hangs until the job is complete
Info: job 729 completed successfully
再次寻求帮助。
答案 0 :(得分:1)
我认为您可以通过Command
继承threading.Thread
来简化事情:
import sys
import subprocess
import threading
cmd = "/path/to/utility -x arg1 -y arg2"
class Command(threading.Thread):
def __init__(self, cmd):
super(Command, self).__init__()
self.cmd = cmd
self.process = None
self.returncode = None
self.jobid = None
def run(self):
print "Starting job..."
self.process = subprocess.Popen(self.cmd, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, shell=True)
out, err = self.process.communicate()
self.jobid = out.split()[10]
def alive(self):
if self.process.poll():
return True
else:
return False
def getJobID(self):
return self.jobid
job = Command(cmd)
job.start()
if job.alive():
print "Job is still alive."
else:
print "Job is not alive."
sys.exit(0)
在命令实际退出之前,您不能使用self.process.communicate()
来获取作业ID,因为communicate()
将阻塞,直到程序完成。相反,您需要直接从流程“stdout
:
self.process = subprocess.Popen(self.cmd, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, bufsize=0, shell=True)
out = self.process.stdout.readline()
self.jobid = out.split()[10]
请注意,添加了bufsize=0
,因此请尽量避免子进程缓冲其输出,这可能导致readline
阻塞。
然后,您可以致电communicate
或wait
等待流程结束:
self.returncode = self.process.wait()