如何同步Python子进程的输出

3 投票
2 回答
5099 浏览
提问于 2025-04-16 01:00

我觉得我在同时运行两个Popen时遇到了同步输出的问题。看起来这两个不同命令的输出混在了一起。我还尝试使用RLock来防止这种情况发生,但没有成功。

一个示例输出可能是:

cmd1
cmd1
cmd2
cmd2
cmd2
cmd2
cmd1
cmd2

代码如下:

import subprocess
import threading

class PopenWorkerThread(threading.Thread):
    def __init__(self, cmdLine):
        self.lock = threading.RLock()
        self.WebSphereCmdLine = cmdLine
        threading.Thread.__init__(self)

    def run(self):
        logger.error('Runninf: ' + self.WebSphereCmdLine)
        proc = subprocess.Popen(self.WebSphereCmdLine, shell=False, stdout=subprocess.PIPE)
        while True:
            self.lock.acquire()
            print proc.stdout.readline()
            self.lock.release()

def launch():
    commandLine = ['ls -l', 'netstat']
    for cmdLine in commandLine:
        workerThread = PopenWorkerThread(cmdLine)
        workerThread.start()

launch()

有没有办法让输出同步,这样看起来就像这样?

cmd1
cmd1
cmd1
cmd1
cmd1
cmd2
cmd2
cmd2
cmd2
cmd2

2 个回答

1

你现在是按行来锁定的,所以一个线程的行和另一个线程的行会交替出现。只要你愿意等到一个进程结束后再显示它的输出,你就可以用更大的“进程”粒度来锁定。当然,你必须在两个线程中使用同一个锁——如果每个线程都用一个完全不同的锁,就像你现在这样,显然是无法实现任何效果的。

所以,举个例子:

import subprocess
import threading

class PopenWorkerThread(threading.Thread):

    lock = threading.RLock()  # per-class, NOT per-instance!

    def __init__(self, cmdLine):
        self.WebSphereCmdLine = cmdLine
        threading.Thread.__init__(self)

    def run(self):
        logger.error('Runninf: ' + self.WebSphereCmdLine)
        proc = subprocess.Popen(self.WebSphereCmdLine, shell=False, stdout=subprocess.PIPE)
        result, _ = proc.communicate()
        with self.lock:
            print result,

def launch():
    commandLine = ['ls -l', 'netstat']
    for cmdLine in commandLine:
        workerThread = PopenWorkerThread(cmdLine)
        workerThread.start()

launch()
1

撰写回答