简体   繁体   English

为什么输出显示顺序错误?

[英]Why does output appear in wrong order?

I'm trying to write a Groovy script that wraps another command and am having trouble with the stdout/stderr order. 我正在尝试编写一个包装另一个命令的Groovy脚本,并且在stdout / stderr命令上遇到麻烦。 My script is below: 我的脚本如下:

#!/usr/bin/env groovy
synchronized def output = ""
def process = "qrsh ${args.join(' ')}".execute()

def outTh = Thread.start {
  process.in.eachLine {
    output += it
    System.out.println "out: $it"
  }
}

def errTh = Thread.start {
  process.err.eachLine {
    output += it
    System.err.println "err: $it"
  } 
} 

outTh.join()
errTh.join()
process.waitFor()
System.exit(process.exitValue())

My problem is that the output doesn't appear on the terminal in the correct order. 我的问题是输出没有以正确的顺序出现在终端上。 Below is the wrapper's output. 下面是包装器的输出。

[<cwd>] wrap.groovy -cwd -V -now n -b y -verbose ant target
waiting for interactive job to be scheduled ...
Your interactive job 2831303 has been successfully scheduled.
Establishing builtin session to host <host> ...
Buildfile: build.xml

BUILD FAILED
Target "target" does not exist in the project "null". 

Total time: 0 seconds
Your job 2831303 ("wrap.groovy") has been submitted

Below is the unwrapped command output. 以下是展开的命令输出。

[<cwd>] qrsh -cwd -V -now n -b y -verbose ant target
Your job 2831304 ("ant") has been submitted
waiting for interactive job to be scheduled ...
Your interactive job 2831303 has been successfully scheduled.
Establishing builtin session to host host ...
Buildfile: build.xml

BUILD FAILED
Target "target" does not exist in the project "null". 

Total time: 0 seconds

Why does the "Your job has been submitted" message appear as the first line in one cast and the last line in another? 为什么“您的作业已提交”消息在一个演员表中显示为第一行,而在另一个演员表中显示为最后一行? I'm guessing it's related to Java libraries, not Groovy. 我猜它与Java库有关,而不与Groovy有关。

This is because of buffering. 这是由于缓冲。 The threads which read stdout and stderr will not process the output the moment it is written by the child process. 读取stdout和stderr的线程在子进程写入输出时将不会处理该输出。 Instead, both streams are buffered, so your process won't see anything unless the child flushes the streams). 相反,两个流都被缓冲,因此除非子进程刷新流,否则您的进程将看不到任何东西

When the data is on the way, which thread gets the CPU first? 当数据在传输中时,哪个线程首先获取CPU? There is no way to tell. 没有办法告诉。 Even if the data for stderr arrives a few milliseconds before stdout, if the stdout thread has the CPU right now, it will get its data first. 即使stderr的数据在stdout之前几毫秒到达,如果stdout线程现在具有CPU,它将首先获取其数据。

What you could do is use Java NIO (channels) and a single thread and first process all output from stderr but that still wouldn't guarantee that the order is preserved. 您可以做的是使用Java NIO(通道)和一个线程,并首先处理stderr的所有输出,但这仍然不能保证顺序得到保留。 Because of the buffering between child and parent process, you could get 4KB of text from one stream before you see a single byte of the other. 由于子进程和父进程之间存在缓冲,因此您可以在看到另一个字节之前从一个流中获取4KB文本。

Unfortunately, there is no cross-platform solution because Java doesn't have an API to merge the two streams into one. 不幸的是,由于Java没有将两个流合并为一个的API,所以没有跨平台的解决方案。 On Unix, you could run the command with sh -c cmd 2>&1 . 在Unix上,可以使用sh -c cmd 2>&1运行命令。 That would redirect stderr to stdout. 这样会将stderr重定向到stdout。 In the parent process, you could then just read stdout and ignore stderr. 在父进程中,您可以只读取stdout并忽略stderr。

The same works for OS X (since it's Unix based). 对于OS X也是如此(因为它基于Unix)。 On Windows, you could install Perl or a similar tool to run the process; 在Windows上,您可以安装Perl或类似的工具来运行该过程。 that allows you to mess with the file descriptors. 这样您就可以弄乱文件描述符。

PS: Pray that args never contains spaces. PS:祈祷args永远不要包含空格。 String.execute() is a really bad way to run a process; String.execute()是运行进程的一种非常糟糕的方法。 use java.lang.ProcessBuilder instead. 请改用java.lang.ProcessBuilder

Try putting System.out.flush after you do your println. 完成println之后,尝试将System.out.flush放入。 If I am right, the messages are appearing in different orders because the System.out is being buffered. 如果我是对的,则由于System.out正在缓冲,因此消息以不同的顺序出现。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM