Slide 1

Slide 1 text

© 2024, ВСЕ ПРАВА ЗАЩИЩЕНЫ Подход к переиспользованию GO-библиотеки в Python Махмуд Кудусов backend-разработчик, операционная команда b2b

Slide 2

Slide 2 text

Давайте знакомиться Махмуд Кудусов Backend-разработчик 4 года в Иви © 2024, ВСЕ ПРАВА ЗАЩИЩЕНЫ

Slide 3

Slide 3 text

№1 среди работодателей 830+ Экспертов и профессионалов 14 Лет на рынке Иви сегодня Производство собственного контента Сильный бренд Собственная технологическая платформа Лояльная вовлечённая аудитория

Slide 4

Slide 4 text

Повестка доклада 1. 2. Зачем нам понадобилось вызывать GO библиотеку из Python? Рассмотрим на примерах, как это можно организовать Попытаюсь убедить вас, насколько неудобным становится код, когда функции начинают принимать и возвращать чуть более сложные структуры данных 4. 5. 6. Поговорим про варианты, как можно облегчить себе жизнь в таких случаях Проведем сравнительный анализ скорости выполнения и объема потребляемой памяти Подведем итоги 3.

Slide 5

Slide 5 text

Зачем нам это? Дано Реализовать 2 библиотеки на Python и GO с абсолютно идентичным предоставляемым функционалом Планируется внедрить библиотеку во множество микросервисов Библиотека хранит в памяти большой объем данных Чем компактнее будем хранить данные (особенно актуально для Python) – тем лучше Чем раньше реализуем – тем лучше

Slide 6

Slide 6 text

Зачем нам это? Идея А почему бы не сделать реализацию на одном языке, и вызывать это из другого? Какие есть варианты: Решили основную логику реализовать на Go. Почему? Go быстрее Типы данных в Golang занимают меньше памяти Реализовать на Python и переиспользовать в Go Реализовать на GO и переиспользовать в Python

Slide 7

Slide 7 text

CGO – пакет в Go, позволяющий вызывать C из GO, и наоборот экспортировать методы, которые могут вызываться из C Python очень неплохо справляется с вызовом динамических библиотек С Как это работает?

Slide 8

Slide 8 text

Небольшой пример Билдим динамическую библиотеку

Slide 9

Slide 9 text

Содержимое _main.h Вызов из Python Небольшой пример

Slide 10

Slide 10 text

Запускаем пример и радуемся, что все работает На первый взгляд никаких сложностей – все круто Далее попробуем реализовать функцию, которая возвращает чуть более сложную структуру Небольшой пример

Slide 11

Slide 11 text

No content

Slide 12

Slide 12 text

Возврат более сложной структуры Такого же магического комментария export для GO- структур cgo не предоставляет Нужно описать необходимую нам структуру в виде C-структуры Описываем нужную нам структуру прямо в .go файле CGO сам распарсит, и раскинет в .h файл

Slide 13

Slide 13 text

Дожили и до ручного управления памяти в Golang :( Не стоит забывать, что все что мы тут выделили, надо будет почистить Возврат более сложной структуры

Slide 14

Slide 14 text

В Python выглядит все сильно цивильнее Важно, чтобы порядок полей в _fields_ соответствовал порядку полей структуры С Возврат более сложной структуры

Slide 15

Slide 15 text

Подчищаем за собой не забыл почистить за собой?

Slide 16

Slide 16 text

Мы привыкли писать на Python и GO, где сборщик мусора подчищает за тобой При разрастании и/или усложнении структуры, увеличивается вероятность что-то не дочистить Сложные приведения типов/структур GO -> C -> Python и Python -> C -> GO (а это была только верхушка айсберга) Разработчикам, не знакомым с языком C, сложно это поддерживать Минусы такого подхода 1. 2. 3. 4.

Slide 17

Slide 17 text

Более удобный механизм возвращать структуры из GO Минимизировать логику конвертации типов и структур Python -> C -> GO и GO -> C -> Python Минимизировать ручное выделение/освобождение памяти Чего хотим? Как можно этого добиться? Передавать в функции и возвращать из них сериализованные json Передавать в функции и возвращать из них сериализованные protobuf-сообщения

Slide 18

Slide 18 text

Схема с proto-сообщениями

Slide 19

Slide 19 text

Опишем аналогичные protobuf-структуры: Схема с proto-сообщениями

Slide 20

Slide 20 text

Схема с proto-сообщениями

Slide 21

Slide 21 text

Плюсы и минусы такого подхода Не надо описывать все в C структурах Не надо реализовывать сложную логику по конвертации типов и структур Не надо выделять память вручную Проще процесс зачистки памяти за собой Плюсы Накладные расходы на сериализацию /десериализацию объектов Минусы

Slide 22

Slide 22 text

Сравнение времени вызова функций Подход с обменом protobuf ~23% хуже по скорости

Slide 23

Slide 23 text

Для проверки производительности реализовал на Python и GO идентичную логику А что по производительности? Сигнатура реализованной функции такая: Для одного элемента выполняются следующие действия: 1. 2. 3. две операции проверки вхождения во множество три операции get из словаря три операции нахождения полного пересечения множеств

Slide 24

Slide 24 text

Сравнение Python, Python + GO, GO

Slide 25

Slide 25 text

Сравнение потребляемой памяти Храним 50000 объектов следующего типа Python-приложение потребляет 3.6 GB GO потребляет 1.1 GB Разница ~3.5 раза

Slide 26

Slide 26 text

Оправдались ли наши ожидания? Итоги Не писать одну и ту же логику дважды Python-библиотека требует меньше памяти, чем могла бы В каких-то моментах Python библиотека даже ускорилась Новые доработки требуют в два раза меньше времени

Slide 27

Slide 27 text

Выоды Вызов GO библиотек из Python вполне жизнеспособный вариант Можно сильно упростить разработку / поддержку /жизнь используя унифицированные описания (в нашем случае протобаф) Стали бы мы такое делать, если бы не было необходимости в реализации GO библиотеки? Скорее всего, нет

Slide 28

Slide 28 text

Вопросы?

Slide 29

Slide 29 text

Увидимся! Твой