Имейте также в виду, что буферизация потоков ввода-вывода и взаимоблокировки являются более общими проблемами, которые затрагивают не только файлы-обертки сокетов. Мы уже исследовали эту тему в главе 5. Однако, в качестве краткого напоминания, в примере 12.15 приводится сценарий, не использующий сокеты, в котором режим полной буферизации не действует, когда его стандартный поток вывода подключен к терминалу (когда сценарий запускается из командной строки, его вывод буферизуется построчно), и действует, когда он подключен к чему-то другому (включая сокет или канал).
Пример 12.15. PP4E\Internet\Sockets\pipe-unbuff-writer.py
# вывод с построчной буферизацией (небуферизованный), когда stdout подключен # к терминалу; при подключении к другим устройствам по умолчанию выполняется # полная буферизация: используйте —u или sys.stdout.flush(), чтобы избежать # задержки вывода в канал/сокет
import time, sys
for i in range(5): # режим буферизации потока влияет на print
print(time.asctime()) # и на прямые операции доступа к файлу потока sys.stdout.write(‘spam\n’) # если sys.stdout не был переустановлен time.sleep(2) # в другой файл
Несмотря на то, что в Python 3.X функция print требует, чтобы файл был открыт в текстовом режиме, в версии 3.X по-прежнему можно подавить полную буферизацию потока вывода с помощью флага —u. Использование этого флага в примере 12.16 заставляет сообщения, которые порождаемый сценарий печатает каждые 2 секунды, появляться по мере того, как они отправляются в поток вывода. В случае отсутствия этого флага выводимые данные появляются все сразу через 10 секунд, когда дочерний сценарий завершит работу, если только он не вызывает sys.stdout.flush в каждой итерации.
Пример 12.16. PP4E\Internet\Sockets\pipe-unbuff-reader.py
# вывод появится только через 10 секунд, если не использовать флаг Python —u # или sys.stdout.flush(); однако вывод будет появляться каждые 2 секунды, # если использовать любой из этих двух вариантов
import os # итератор читает
for line in os.popen(‘python —u pipe—unbuff—writer.py‘): # строки print(line, end=») # блокируется без —u!
Ниже приводится вывод этого сценария. В отличие от примеров с сокетами, он автоматически запускает пишущий сценарий, поэтому нам не требуется открывать отдельное окно консоли для тестирования. В главе 5 говорилось, что функция os.popen также принимает аргумент buffering, как и метод socket.makefile, но он не оказывает влияния на буферизацию потоков ввода-вывода порождаемых программ и поэтому не может предотвратить буферизацию потока вывода в подобных ситуациях.
C:\…\PP4E\Internet\Sockets> pipe-unbuff-reader.py
Wed Apr 07 09:32:28 2010
spam
Wed Apr 07 09:32:30 2010 spam
Wed Apr 07 09:32:32 2010 spam
Wed Apr 07 09:32:34 2010 spam
Wed Apr 07 09:32:36 2010
spam
Таким образом, ключ —u по-прежнему можно использовать в версии 3.X для решения проблемы буферизации при соединении программ, если только стандартным потокам в порождаемых программах не назначаются другие объекты, как это делается в примере 12.11 для перенаправления потоков ввода-вывода в сокеты. В случае перенаправления в сокеты может потребоваться вручную вызывать метод flush или заменить обертки сокетов.
Использованная литература:
Марк Лутц — Программирование на Python, 4-е издание, II том, 2011