Большая часть обработки данных может быть предусмотрена как конвейер компонентов, выход одного из которых подается на вход другого. Типичный конвейер обработки:
reader | handler | writer
Как фольга для начала этого обсуждения, рассмотрим объектно-ориентированную реализацию этого конвейера, где каждый сегмент является объектом. Объект handler
содержит ссылки на объекты reader
и writer
и имеет метод run
, который выглядит так:
define handler.run:
while (reader.has_next) {
data = reader.next
output = ...some function of data...
writer.put(output)
}
Схематически зависимости:
reader <- handler -> writer
Теперь предположим, что я хочу вставить новый сегмент конвейера между считывателем и обработчиком:
reader | tweaker | handler | writer
Опять же, в этой реализации OO tweaker
будет оберткой вокруг объекта reader
, а методы tweaker
могут выглядеть примерно как (в некотором псевдо-императивном коде):
define tweaker.has_next:
return reader.has_next
define tweaker.next:
value = reader.next
result = ...some function of value...
return result
Я нахожу, что это не очень сложная абстракция. Некоторые проблемы:
-
tweaker
может использоваться только с левой стороныhandler
, то есть я не могу использовать приведенную выше реализациюtweaker
для формирования этого конвейера:читатель | обработчик | твикер | автор
-
Я хотел бы использовать ассоциативное свойство конвейеров, чтобы этот конвейер:
читатель | обработчик | автор
может быть выражена как:
reader | p
где p
- конвейер handler | writer
. В этой реализации OO я должен частично создать экземпляр объекта handler
- В некоторой степени из повторения (1), объекты должны знать, если они "толкают" или "тянут" данные.
Я ищу фреймворк (не обязательно OO) для создания конвейеров обработки данных, которые решают эти проблемы.
Я отметил это с помощью Haskell
и functional programming
, потому что я считаю, что функциональные концепции программирования могут быть полезны здесь.
В качестве цели было бы неплохо создать такой конвейер:
handler1
/ \
reader | partition writer
\ /
handler2
В какой-то перспективе оболочки оболочки Unix решают многие из этих проблем с помощью следующих решений:
-
Компоненты трубопровода выполняются асинхронно в отдельных процессах
-
Объекты труб опосредуют передачу данных между "толкателями" и "съемниками"; то есть они блокируют авторов, которые слишком быстро записывают данные и читают, которые слишком быстро читают.
-
Вы используете специальные коннекторы
<
и>
для подключения пассивных компонентов (например, файлов) к конвейеру
Меня особенно интересуют подходы, которые не используют потоковую передачу или передачу сообщений среди агентов. Возможно, это лучший способ сделать это, но я бы хотел, если возможно, избегать потоковой передачи.
Спасибо!