У меня есть функция, которая внутри lauches несколько потоков работает параллельно. Нити печатают что-то, и я хочу захватить этот вывод из внешней функции. Я попытался использовать следующий код для вывода результатов:
import sys, io
stdout = sys.stdout
sys.stdout = io.StringIO()
threads_conn(connect, devices) #- here many threads starts with many print inside
output = sys.stdout.getvalue()
sys.stdout = stdout
print(output)
Этот код работает. Но проблема в том, что вывод печатается только тогда, когда все ад заполняются. Поэтому у меня есть заморозка. Как только все потоки будут выполнены, будет напечатан весь вывод. То, что я хотел бы иметь, - иметь выход, когда он генерируется внутри - другими словами, в режиме реального времени. Теперь у меня есть весь выходной буфер, напечатанный сразу. Как получить все потоки для вывода в режиме реального времени?
То, что вы хотите сделать, это написать собственный класс TextIOBase
(или, если вам нужны двоичные данные, напишите свой собственный RawIOBase
а затем оберните вокруг него TextIOWrapper
), где вы можете поместить любое поведение, которое вы хотите.
Как вы можете видеть из документов. все, что вам нужно реализовать для TextIOBase
является detach
, read
, readline
, и write
. И первые три не имеют отношения к тому, что вы делаете.
Итак, что должно выглядеть ваша write
? Ну, это зависит от того, что вы хотите сделать.
это звучит так, как ваша цель состоит в том, чтобы доработать все как на реальном уровне, так и на StringIO
. Если это так, это довольно тривиально.
Единственный вопрос - это то, что вы хотите сделать, если одна из целей вызывает исключение или записывает меньшее количество байтов, чем другое, и т.д. Поскольку IOString
никогда не будет делать ничего из этого, мы можем написать что-то действительно немое, что просто предполагает, что независимо от того, что было в действительности, это было правильным решением.
class TeeTextIO(io.TextIOBase):
def __init__(self, target):
self.target = target
self.stringio = io.StringIO()
def write(self, s):
writecount = self.target.write(s)
self.stringio.write(s[:writecount])
return writecount
И сейчас:
stdout = sys.stdout
sys.stdout = TeeTextIO(sys.stdout)
threads_conn(connect, devices) #- here many threads starts with many print inside
output = sys.stdout.stringio.getvalue()
sys.stdout = stdout
Теперь выход StringIO
на реальный stdout
когда он вошел, но он также был сохранен в StringIO
для того, что вы хотите сделать с ним позже.
(Обратите внимание, что этот класс будет работать с любым TextIOBase
, как с open
файлом, а не только с stdout
. Это не стоило нам ничего, чтобы сделать его общим, так почему бы и нет?)
Что делать, если вы хотите сделать что-то совершенно другое, например, распространять каждую write
случайно среди 10 разных файлов? Это должно быть очевидно:
class SpreadTextWriter(io.TextIOBase):
def __init__(self, *files):
self.files = files
def write(self, s):
return random.choice(self.files).write(s)