Год назад и переоденься, я написал это в « Исследовательском программировании ». Оказывается, это было ошибкой. Хотя метод расширения подкласса является отличным способом постепенного создания программы, в долгосрочной перспективе подклассы не рекомендуется.
Чем больше я смотрю на функции генератора Python и идею использования Map-Reduce, тем больше понимаю, что посетители и расширение подкласса — не лучший шаблон проектирования. Такой же вид исследования может быть выполнен с помощью методов сокращения карты, и получающееся в результате приложение несколько проще.
Дизайн муфта
Проблема с проектированием по подклассам заключается в том, что операции преобразования и сокращения часто определяются относительно неформально. В конце концов, это просто вызовы методов в одном классе. Вы можете, не задумываясь, создать неясные зависимости и предположения. Это может сделать посетителя довольно сложным или затруднить рефакторинг в подкласс функций подкласса.
В качестве конкретного примера у нас есть приложение, которое обрабатывает каталоги файлов и файловые архивы (ZIP и TAR) рабочих книг с несколькими листами. Все это вложение просто оборачивает источник строк электронной таблицы. Это должен быть набор простых вложенных операций с картами для преобразования каталогов, файлов, архивов файлов и т. Д. В источник строк электронной таблицы.
Однако на полпути через нашу иерархию классов подкласс ввел объект с состоянием, который могли бы использовать другие функции метода. Однако, когда мы попытались преобразовать вещи в простой посетитель, чтобы посетить все рабочие книги (игнорируя всю директорию, архив и файловую структуру), мы обошли скрытый объект с состоянием, не осознавая этого .
Именованные кортежи и неизменность
Гораздо более чистым решением является использование конструктора namedtuple в Python и создание функций генератора, которые отображают один тип именованных кортежей на другой тип именованных кортежей . Это имеет то преимущество, что — если вы не сделали что-то действительно плохое — вы должны иметь возможность выбирать и удалять каждый кортеж, легко заполняя многопроцессорный конвейер. Максимальный параллелизм, минимальная работа.
Каждый этап в конвейере сокращения карты может иметь следующую форму.
SomeResult = namedtuple('SomeResult',['a','b','c']) for x in someSource(): assert isinstance( x, SomeSource ) yield SomeResult( <i>some transformation of x</i> )
Утверждение должно быть очевидно из проверки функции someSource . Это предоставлено здесь, потому что это важно для создания конвейеров сокращения карт, которые работают. Лучше доказать, что утверждение верно, путем проверки кода и закомментировать утверждение assert .
Pipelining
То, что выскакивает из этого, является объектами без состояния. Поскольку именованные кортежи являются неизменными, кажется, что мы выполнили какое-то чисто функциональное программирование, не потревожив пота.
Кроме того, мы можем увидеть наш путь к инкапсуляции функции генератора, и в результате ее именованный кортеж станет единым объектом MapReduce. Затем утверждение можно вырвать из цикла и преобразовать в менеджер конвейера.
Это может дать нам несколько преимуществ.
- Способ указать конвейер как связанный ряд функций генератора. Например, Трубопровод (генератор_1, карта_2, карта_3, уменьшить_4) .
- Осмотр трубопровода, чтобы убедиться, что ограничения будут выполнены. Заголовок конвейера имеет результирующий тип, все остальные этапы имеют требуемый тип источника и тип результата. Поскольку они называются кортежами, мы заботимся только о том, чтобы обязательные атрибуты были подмножеством атрибутов результата предыдущего этапа.
- Реализация путем инъекций маринада / расслоения обертки вокруг каждой ступени.
- Распределение через «бегунка», который разветвляет конвейер подпроцесса. Это должно привести к операциям сокращения карты, которые затопляют ОС, имея несколько параллельных этапов.
цели
Как правило, наша цель состоит в том, чтобы процессор на 100% выполнял правильные задачи. Либо на 100% выполняю веб-сервисы, либо на 100% выполняю запросы к базе данных, либо на 100% выполняю пакетную обработку массивных наборов данных с плоскими файлами.
В настоящее время мы не можем преодолеть 66%: одно ядро близко к 100%, а другое задействовано незначительно. Перейдя к многопроцессорной обработке, мы сможем выделить процессор с любым количеством ядер.
С http://slott-softwarearchitect.blogspot.com