Обертывание дескрипторов канала объектами файлов

obertyvanie deskriptorov kanala obektami fajlov Системные инструменты параллельного выполнения

При внимательном рассмотрении вывода предыдущего сценария можно заметить, что когда счетчик задержки в дочернем процессе достигает значения 004, родительский процесс получает из канала сразу два сообщения — дочерний процесс записывает два различных сообщения, но на некоторых платформах или при определенных настройках (отличных от тех, что используются здесь) они могут оказаться достаточно близки по времени и получены родителем как один блок данных. В действительности родитель каждый раз слепо запрашивает чтение не более 32 байтов, но получает тот текст, который есть в канале.

Чтобы отделять одно сообщение от другого, можно определить для канала символ-разделитель. Для этого можно использовать символ конца строки, так как можно обернуть дескриптор канала объектом файла с помощью функции os.fdopen и использовать его метод readline для поиска в канале очередного разделителя \n. Кроме того, этот прием позволит использовать более мощные инструменты объектов текстовых файлов, с которыми мы познакомились в главе 4. Такая схема реализована в примере 5.20.

Пример 5.20. PP4E\System\Processes\pipe2.py

#  аналогичен сценарию pipe1.py, но обертывает входной дескриптор канала

#  объектом файла для обеспечения построчного чтения данных,

#  и в обоих процессах закрывает неиспользуемый дескриптор канала

import os, time

def child(pipeout): zzz = 0 while True: time.sleep(zzz) # заставить родителя подождать

msg = (‘Spam %03d\n’ % zzz).encode() # каналыдвоичные файлы в 3.X


parent()

Эта версия расширена тем, что закрывает неиспользуемые концы каналов в каждом процессе (например, после ветвления родительский процесс закрывает свою копию выходного конца канала, в который пишет дочерний процесс); обычно программы должны закрывать неиспользуемые концы каналов. В этой новой версии родителю при каждом чтении из канала гарантированно возвращается одно сообщение дочернего процесса, потому что при записи все они разделяются маркерами:

[C:\..

.\PP4E\System\Processes]$ python pipe2.py

Parent

8204 got [Spam 000] at 1267997789.33

Parent

8204 got [Spam 001] at 1267997790.03

Parent

8204 got [Spam 002] at 1267997792.05

Parent

8204 got [Spam 003] at 1267997795.06

Parent

8204 got [Spam 004] at 1267997799.07

Parent

8204 got [Spam 000] at 1267997799.07

Parent

8204 got [Spam 001] at 1267997800.08

Parent

8204 got [Spam 002] at 1267997802.09

Parent

8204 got [Spam 003] at 1267997805.1

Parent

8204 got [Spam 004] at 1267997809.11

Parent

8204 got [Spam 000] at 1267997809.11

Parent

8204 got [Spam 001] at 1267997810.13

…и так далее: CtrlC для выхода…

 

Обратите внимание, что в этой версии текстовые данные теперь возвращаются в виде объекта str, так как функция os.fdopen по умолчанию устанавливает режим r при открытии файла. Как уже упоминалось, обмен данными через каналы обычно происходит с использованием строк байтов, когда дескрипторы используются непосредственно, с применением инструментов из модуля os, но обертывание дескрипторов объектами файлов позволяет использовать для представления данных строки str. В этом примере декодирование байтов в строку str в родительском процессе выполняется операцией чтения. Использование функции os.fdopen и текстового режима в дочернем процессе позволило бы избежать необходимости кодирования данных вручную, но это кодирование в любом случае выполнялось бы объектом файла (хотя кодирование символов ASCII, как в данном примере, является достаточно тривиальной операцией). Что касается простых файлов, лучший режим обработки данных в канале определяется самой их природой.

Использованная литература:
Марк Лутц — Программирование на Python, 4-е издание, I том, 2011

Оцените статью
Секреты программирования
Добавить комментарий