Как использовать прослушиватели таблиц
Джейк Малфорд
Привет, я Джейк, разработчик программного обеспечения в Deephaven Data Labs в их команде по связям с разработчиками. На протяжении всей своей карьеры я уделял большое внимание расширению возможностей других разработчиков, начиная от работы ассистентом в колледже и заканчивая работой над опытом разработчиков в использовании REST API, а теперь работаю с механизмом запросов Deephaven. Это познакомило меня с различными подходами к разработке программного обеспечения. Сегодня я расскажу о том, как недавний опыт привел меня к мысли о программировании, управляемом событиями.
Программирование, управляемое событиями — очень простая концепция. Разработано программное обеспечение, которое запускается после определенных событий. Этими событиями могут быть любые действия пользователя, HTTP-запросы или события из других потоков. Deephaven имеет встроенную поддержку программирования, управляемого событиями, с помощью слушателей таблиц. Слушатели таблиц позволяют вам писать функции, которые выполняются при изменении исходных таблиц.
Простые слушатели
Начнем с простого примера:
from deephaven import listen from deephaven.TableTools import timeTable
def listener_function(update): print(f"FUNCTION LISTENER: update={update}")
table = timeTable("00:00:01").update("X=i").tail(5) handle = listen(table, listener_function)
Вывод журнала:
FUNCTION LISTENER: update={added={0}, removed={}, modified={}, shifted={}, modifiedColumnSet={}} FUNCTION LISTENER: update={added={1}, removed={}, modified={}, shifted={}, modifiedColumnSet={}} FUNCTION LISTENER: update={added={2}, removed={}, modified={}, shifted={}, modifiedColumnSet={}}
Этот слушатель просто делает оператор печати с информацией, которая изменилась в таблице. Ничего слишком сложного, правда? Таблица обновляется, и информация печатается.
Теперь предположим, что мы хотели сделать разные операторы печати в зависимости от того, было ли добавленное новое число четным или нечетным. Мы могли бы обновить наш listener_function
с некоторой логикой для обнаружения четных и нечетных чисел, и это будет выглядеть так:
def listener_function(update): added_iterator = update.added.iterator()
while added_iterator.hasNext(): index = added_iterator.nextLong() x = table.getColumnSource("X").get(index) if (x % 2 == 0): print("Even number found") else: print("Odd number found")
Вывод журнала:
FUNCTION LISTENER: update={added={3}, removed={}, modified={}, shifted={}, modifiedColumnSet={}}
Это, безусловно, работает, но только потому, что наши «события» — это просто добавление чисел. Если бы это была настоящая система, управляемая событиями, у нас могли бы быть разные функции, которые мы хотели бы выполнять в зависимости от события, и это было бы очень сложно упаковать в одну функцию. Вы можете подумать: «Хорошо, так что вместо этого мы можем написать разные функции на основе значения в обновлении таблицы, и наш listener_function
может содержать логику для вызова правильной функции». Это может выглядеть так:
def print_odd(): print("Odd number found")
def print_even(): print("Even number found")
def listener_function(update): added_iterator = update.added.iterator()
while added_iterator.hasNext(): index = added_iterator.nextLong() x = table.getColumnSource("X").get(index) if (x % 2 == 0): print_even() else: print_odd()
Вывод журнала:
FUNCTION LISTENER: update={added={4}, removed={}, modified={}, shifted={}, modifiedColumnSet={}}
Теперь это больше похоже на традиционную систему, управляемую событиями. Однако с Deephaven вы можете сделать еще один шаг вперед. Для тех, кто не знаком с Deephaven, одной из его основных функций является простота обработки данных в реальном времени. Одним из применений этого является фильтрация данных в режиме реального времени.
Применение слушателей к отфильтрованным таблицам
Вместо того, чтобы содержать условную логику в listener_function
, мы можем использовать фильтры Deephaven, чтобы извлечь эту логику и создать две таблицы (одну для нечетных чисел, а другую для четных чисел), а затем зарегистрировать наши функции print_odd
и print_even
в качестве функций слушателя для этих столы.
from deephaven import listen from deephaven.TableTools import timeTable
def print_odd(update): #Even though we aren't using the update parameter, it is still required to be a listener print("Odd number found")
def print_even(update): print("Even number found")
table = timeTable("00:00:01").update("X=i").tail(5) evens = table.where("X % 2 == 0") odds = table.where("X % 2 == 1")
even_handle = listen(evens, print_even) odd_handle = listen(odds, print_odd)
Вывод журнала:
FUNCTION LISTENER: update={added={7}, removed={2}, modified={}, shifted={}, modifiedColumnSet={}} Even number found FUNCTION LISTENER: update={added={8}, removed={3}, modified={}, shifted={}, modifiedColumnSet={}} Odd number found
Этот подход имеет несколько преимуществ. Нам больше не нужен общий listener_function
, содержащий условную логику; эта логика была перенесена в методы фильтрации Deephaven. Это позволяет нам использовать более простые функции слушателя для наших таблиц.
Поскольку у нас нет цепочки операторов if-else, мы можем добавлять дополнительные обработчики без изменения существующего кода. Например, если нам нужен новый обработчик для чисел, кратных 3, все, что нам нужно сделать, это:
- создать новую таблицу на основе фильтра нашей существующей таблицы,
- создать новую функцию слушателя,
- и зарегистрируйте эту функцию прослушивателя в таблице.
def print_threes(update): print("Multiple of 3 found")
threes = table.where("X % 3 == 0")
threes_handler = listen(threes, print_threes)
Вывод журнала:
FUNCTION LISTENER: update={added={9}, removed={4}, modified={}, shifted={}, modifiedColumnSet={}} Even number found FUNCTION LISTENER: update={added={10}, removed={5}, modified={}, shifted={}, modifiedColumnSet={}} Odd number found Multiple of 3 found
Цепочка условных операторов также проще. Допустим, у нас есть особый случай, и нам нужен дополнительный оператор печати для нечетных чисел, кратных 5. С условными операторами для этого нам понадобится вложенный оператор if-else. Но с Deephaven мы можем создать новую таблицу нечетных чисел, кратных 5, на основе нашей существующей таблицы нечетных чисел и создать прослушиватель для этой таблицы.
def print_odd_fives(update): print("Odd multiple of 5 found")
odd_fives = odds.where("X % 5 == 0")
odd_fives_handler = listen(odd_fives, print_odd_fives)
Вывод журнала:
FUNCTION LISTENER: update={added={11}, removed={6}, modified={}, shifted={}, modifiedColumnSet={}} Even number found FUNCTION LISTENER: update={added={12}, removed={7}, modified={}, shifted={}, modifiedColumnSet={}} Even number found Odd number found Multiple of 3 found Odd multiple of 5 found FUNCTION LISTENER: update={added={13}, removed={8}, modified={}, shifted={}, modifiedColumnSet={}} Even number found Odd number found Multiple of 3 found
Слушатели Deephaven чрезвычайно эффективны, и знакомство с ними вместе с языком запросов Deephaven было отличным для разработки другого взгляда на проблемы и их решения.
Загляните к нам на нашу домашнюю страницу https://deepphaven.io/, и я приглашаю вас присоединиться к нам в Slack!
Дополнительные материалы на PlainEnglish.io. Подпишитесь на нашу бесплатную еженедельную рассылку новостей. Подпишитесь на нас в Twitter и LinkedIn. Присоединяйтесь к нашему сообществу Discord.