Статьи

Map-Reduce, Python и именованные кортежи

Год назад и переоденься, я написал это в « Исследовательском программировании ». Оказывается, это было ошибкой. Хотя метод расширения подкласса является отличным способом постепенного создания программы, в долгосрочной перспективе подклассы не рекомендуется.

Чем больше я смотрю на функции генератора 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. Способ указать конвейер как связанный ряд функций генератора. Например, Трубопровод (генератор_1, карта_2, карта_3, уменьшить_4) .
  2. Осмотр трубопровода, чтобы убедиться, что ограничения будут выполнены. Заголовок конвейера имеет результирующий тип, все остальные этапы имеют требуемый тип источника и тип результата. Поскольку они называются кортежами, мы заботимся только о том, чтобы обязательные атрибуты были подмножеством атрибутов результата предыдущего этапа.
  3. Реализация путем инъекций маринада / расслоения обертки вокруг каждой ступени.
  4. Распределение через «бегунка», который разветвляет конвейер подпроцесса. Это должно привести к операциям сокращения карты, которые затопляют ОС, имея несколько параллельных этапов.

цели

Как правило, наша цель состоит в том, чтобы процессор на 100% выполнял правильные задачи. Либо на 100% выполняю веб-сервисы, либо на 100% выполняю запросы к базе данных, либо на 100% выполняю пакетную обработку массивных наборов данных с плоскими файлами.

В настоящее время мы не можем преодолеть 66%: одно ядро ​​близко к 100%, а другое задействовано незначительно. Перейдя к многопроцессорной обработке, мы сможем выделить процессор с любым количеством ядер.

С http://slott-softwarearchitect.blogspot.com