Почему выходные данные отображаются в неправильном порядке?

java groovy

1464 просмотра

2 ответа

Я пытаюсь написать скрипт Groovy, который оборачивает другую команду, и у меня возникают проблемы с порядком stdout / stderr. Мой скрипт ниже:

#!/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())

Моя проблема в том, что вывод не появляется на терминале в правильном порядке. Ниже вывод обёртки.

[<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

Ниже приведен распакованный вывод команды.

[<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

Почему сообщение «Ваша работа отправлена» отображается в виде первой строки в одном приведении и последней строки в другом? Я предполагаю, что это связано с библиотеками Java, а не с Groovy.

Автор: dromodel Источник Размещён: 13.11.2019 11:30

Ответы (2)


6 плюса

Это из-за буферизации. Потоки, которые читают stdout и stderr, не будут обрабатывать выходные данные в тот момент, когда они записаны дочерним процессом. Вместо этого оба потока буферизуются, поэтому ваш процесс ничего не увидит, пока дочерний процесс не сбросит потоки).

Когда данные находятся в пути, какой поток получает процессор первым? Там нет никакого способа, чтобы сказать. Даже если данные для stderr поступают за несколько миллисекунд до stdout, если поток stdout имеет ЦП прямо сейчас, он сначала получит свои данные.

То, что вы можете сделать, это использовать Java NIO (каналы) и один поток и сначала обработать весь вывод из stderr, но это все равно не будет гарантировать сохранение порядка. Из-за буферизации между дочерним и родительским процессами вы можете получить 4 КБ текста из одного потока, прежде чем увидите один байт другого.

К сожалению, нет кроссплатформенного решения, потому что у Java нет API для объединения двух потоков в один. В Unix вы можете запустить команду с sh -c cmd 2>&1. Это перенаправило бы stderr на стандартный вывод. В родительском процессе вы можете просто прочитать stdout и проигнорировать stderr.

То же самое работает для OS X (так как она основана на Unix). В Windows вы можете установить Perl или аналогичный инструмент для запуска процесса; это позволяет вам связываться с файловыми дескрипторами.

PS: Молитесь, чтобы argsникогда не было пробелов. String.execute()действительно плохой способ запустить процесс; используйте java.lang.ProcessBuilderвместо

Автор: Aaron Digulla Размещён: 10.02.2011 04:18

1 плюс

Попробуйте поместить System.out.flush после того, как вы выполните свою печать. Если я прав, сообщения появляются в разных порядках, потому что System.out буферизуется.

Автор: Tim Размещён: 10.02.2011 04:18
Вопросы из категории :
32x32