У меня есть оболочка вокруг readCreateProcessWithExitCode
, которая выполняет ранний выход всякий раз, когда возвращается ненулевой код выхода, и возвращает вывод stdout
import System.Process
runShell :: String -> String -> IO String
runShell cmd msg = do
(ec, r, err) <- readCreateProcessWithExitCode (shell cmd) ""
when (isFailure ec) (error $ msg <> ": " <> err)
return r
На странице документации readCreateProcessWithExitCode
кажется похожим на более простой readProcess
, который утверждает, что блокируется до завершения разветвленного процесса.
Теперь проблема возникает всякий раз, когда я пытаюсь чередовать журналы stdout
с помощью putStrLn
.
fn :: IO ()
fn = do
void $ runShell "lightweight" "err1"
print "log1"
void $ runShell "expensive" "err2"
print "log2"
Предполагая, что обе команды выполнены успешно, а выполнение второй занимает несколько секунд, функция должна записать "log1"
почти сразу после запуска lightweight
, подождать несколько секунд, а затем вывести "log2"
. Однако это не так — кажется, что журналы «приостанавливаются» и печатаются только в конце выполнения программы, все сразу.
Я думал, что ленивая оценка как-то связана с этим, но явная оценка результатов putStrLn
тоже не помогла.
() <- putStrLn "log1"
@WillemVanOnsem Вы абсолютно правы. hSetBuffering stdout NoBuffering
кажется, проблема решена
Имейте в виду, что отключение буферизации может отрицательно сказаться на производительности, если вывод большой. Попробуйте запустить hFlush stdout
после print
. (Кроме того, используйте вместо этого putStrLn "..."
, если вы не хотите, чтобы строки заключались в кавычки и экранировались)
Как отметил Виллем Ван Онсем в комментарии, по умолчанию происходит некоторая буферизация с stdout
. Его можно отключить с помощью
hSetBuffering stdout NoBuffering
LineBuffering
, вероятно, является лучшим компромиссом между эффективностью и оперативностью, чем NoBuffering
. Это значение по умолчанию для stdout, если только вы не запускаете свою программу необычным образом, например. как часть трубопровода.
Я не уверен, что это ленивая оценка. Возможно, это просто буферизация результата. В зависимости от оболочки, операционной системы и обработчика, запись данных в стандартный вывод сама по себе не сразу печатается в оболочке.