В библиотеках C (и, следовательно, c на основе python) потоки обрабатываются по-разному в зависимости от того, подключены они к интерактивным терминалам (или что-то притворяется) или нет. Для tty
, stdout
является буферизованной строкой, в противном случае его блок буферизуется и сбрасывается в дескриптор файла только при достижении некоторой границы блока. Когда вы перенаправлены на PIPE, поток больше не является tty, и действует блочная буферизация.
Решение состоит в том, чтобы снова открыть stdout
, указав, что вы хотите буферизацию строки (1) независимо от этого. На уровне C, stderr
всегда буферизуется строкой, но когда я тестировал только повторное открытие stdout
, программа действовала так, как если бы stderr
была буферизована блоком. Я был довольно удивлен. Может быть, это промежуточный слой io.TextIO
или какая-то другая странная вещь, но я обнаружил, что мне нужно исправить обе трубы.
Даже если stdout
и stderr
go к одной трубе, они отдельные файловые дескрипторы с отдельными буферами в отношении исполняемой программы. Вот почему перемежение не происходит естественным образом в выходном буфере даже в блочном режиме.
#!/usr/bin/env python3
import sys
import os
# reopen stdout line buffered
sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 1)
# this surprises me, seems like we have to reopen stderr
# line buffered, but i thought it was line buffered anywy.
# perhaps its the intermediate python TextIO layer?
sys.stderr = os.fdopen(sys.stderr.fileno(), 'w', 1)
count = 0
sys.stderr.write('stderr, order %d\n' % count)
count += 1
sys.stdout.write('stdout, order %d\n' % count)
count += 1
sys.stderr.write('stderr, order %d\n' % count)
count += 1
sys.stdout.write('stdout, order %d\n' % count)