Advertisement
  1. Code
  2. Go

Написание плагинов в Go

by
Read Time:8 minsLanguages:

Russian (Pусский) translation by Masha Kolesnikova (you can also view the original English article)

Go не может загрузить код динамически до версии 1.8. Я большой сторонник систем на основе плагинов, которые во многих случаях требуют динамической загрузки. В какой-то момент я даже подумал о написании пакета плагинов, основанного на C-интеграции

Я очень рад, что дизайнеры Go добавили эту возможность в язык. В этом руководстве вы узнаете, почему плагины так важны, какие платформы поддерживаются в настоящее время, а также как создавать, собирать, загружать и использовать плагины в своих программах.

Обоснование для Go плагинов

Плагины Go могут быть использованы для многих целей. Они позволяют вам разбить вашу систему на общий механизм, который легко понять и тестировать, и многие плагины придерживаются строгого интерфейса с четко определенными обязанностями. Плагины могут быть разработаны независимо от основной программы, которая их использует.

Программа может использовать различные комбинации плагинов и даже несколько версий одного и того же плагина одновременно. Четкие границы между основной программой и плагинами способствуют лучшей практике слабой связи и разделения проблем.

Пакет "plugin"

Новый пакет "plugin", представленный в Go 1.8, имеет очень узкую область применения и интерфейс. Он предоставляет функцию Open() для загрузки разделяемой библиотеки, которая возвращает объект Plugin. У объекта Plugin есть функция Lookup(), которая возвращает Symbol (пустой интерфейс {}), поэтому тип может быть указан в функции или переменной, предоставляемой плагином. Вот и все.

Поддержка платформы

В настоящее время пакет плагинов поддерживается только в Linux. Но есть способы, как вы увидите, поиграть с плагинами в любой операционной системе.

Подготовка Docker-среды

Если вы разрабатываете для Linux-системы, вам просто нужно установить Go 1.8, и все готово. Но если вы работаете в Windows или macOS, вам нужен контейнер Linux VM или Docker. Чтобы использовать его, вы должны сначала установить Docker.

После установки Docker откройте консольное окно и введите: docker run -it -v ~ / go: / go golang: 1.8-wheezy bash

Эта команда отображает мой локальный $GOPATH в ~/go на /go внутри контейнера. Это позволяет мне редактировать код, используя мои любимые инструменты на хосте, и иметь его в контейнере для сборки и запуска в среде Linux.

Для получения дополнительной информации о Docker, посмотрите мою серию «Докер с нуля» здесь на Envato Tuts +:

Создание Go Plugin

Плагин Go выглядит как обычный пакет, и вы можете использовать его как обычный пакет. Он становится плагином только тогда, когда вы создаете его как плагин. Вот пара плагинов, которые реализуют функцию Sort(), которая сортирует часть целых чисел.

QuickSort Plugin

Первый плагин реализует наивный алгоритм QuickSort. Реализация работает на срезах с уникальными элементами или с дубликатами. Возвращаемое значение - указатель на фрагмент целых чисел. Это полезно для функций сортировки, которые сортируют свои элементы на месте, потому что позволяет избежать копирования.

В этом случае я фактически создаю несколько промежуточных срезов, поэтому эффект в основном теряется. Я жертвую производительностью ради удобочитаемости, поскольку цель состоит в том, чтобы продемонстрировать плагины, а не реализовать суперэффективный алгоритм. Логика выглядит следующим образом:

  • Если имеется ноль элементов или один элемент, вернуть исходный фрагмент (уже отсортированный).
  • Выберите случайный элемент в качестве колышка.
  • Добавьте все элементы, которые меньше колышка, к нижнему срезу.
  • Добавьте все элементы, которые больше, чем колышек выше среза.
  • Добавьте все элементы, которые равны колышку, к среднему срезу.

На этом этапе средний срез сортируется, потому что все его элементы равны (если были дубликаты колышка, здесь будет несколько элементов). Теперь наступает рекурсивная часть. Он сортирует нижние и верхние фрагменты, снова вызывая Sort(). Когда эти вызовы вернутся, все фрагменты будут отсортированы. Затем, просто добавив их, вы получите полный вид оригинального фрагмента.

Плагин BubbleSort

Второй плагин реализует алгоритм BubbleSort наивным способом. BubbleSort часто считают медленным, но для небольшого количества элементов и с некоторой незначительной оптимизацией он часто опережает более сложные алгоритмы, такие как QuickSort.

На самом деле обычно используется алгоритм гибридной сортировки, который начинается с QuickSort, и когда рекурсия достигает достаточно небольших массивов, алгоритм переключается на BubbleSort. Плагин пузырьковой сортировки реализует функцию Sort() с той же сигнатурой, что и алгоритм быстрой сортировки. Логика выглядит следующим образом.

  • Если имеется ноль элементов или один элемент, вернуть исходный фрагмент (уже отсортированный).
  • Перебераем все элементы.
  • В каждой итерации перебираем все остальные элементы.
  • Меняем местами текущий элемент на любой элемент большего размера.
  • В конце каждой итерации текущий элемент будет на своем месте.

Сборка плагина

Теперь у нас есть два плагина, которые мы должны построить, чтобы создать разделяемую библиотеку, которая может быть загружена динамически нашей основной программой. Команда для сборки: go build -buildmode = plugin

Поскольку у нас есть несколько плагинов, я поместил каждый из них в отдельный каталог в общем каталоге "plugins". Вот расположение каталога плагинов. В каждом подкаталоге плагина есть исходный файл "<attribute> _plugin.go" и небольшой сценарий оболочки "build.sh" для сборки плагина. Последние файлы .so помещаются в родительский каталог plugins:

Причина, по которой файлы * .so попадают в каталог плагинов, заключается в том, что они могут быть легко обнаружены основной программой, как вы увидите позже. Фактическая команда сборки в каждом сценарии «build.sh» указывает, что выходной файл должен идти в родительский каталог. Например, для плагина пузырьковой сортировки это:

go build -buildmode=plugin -o ../bubble_sort_plugin.so

Загрузка плагина

Загрузка плагина требует знания того, где найти целевые плагины (общие библиотеки * .so). Это можно сделать различными способами:

  • передача аргументов командной строки
  • установка переменной среды
  • используя хорошо-известный каталог
  • используя файл конфигурации

Другая проблема заключается в том, знает ли основная программа имена плагинов или динамически обнаруживает все плагины в определенном каталоге. В следующем примере программа ожидает, что в текущем рабочем каталоге будет находиться подкаталог с именем plugins, и загружает все плагины, которые найдет.

Вызов функции filepath.Glob("plugins/*.so") возвращает все файлы с расширением ".so" в подкаталоге plugins, а plugin.Open(filename) загружает плагин. Если что-то пойдет не так, программа паникует.

Использование плагина в программе

Поиск и загрузка плагина - это только полдела. Плагин-объект предоставляет метод Lookup(), который по имени символа возвращает интерфейс. Вам нужно перевести этот интерфейс в конкретный объект (например, функцию, подобную Sort()). Нет никакого способа узнать, какие символы доступны. Вам просто нужно знать их имена и их тип, чтобы вы могли правильно ввести assert.

Когда символ является функцией, вы можете вызывать его как любую другую функцию после успешного утверждения типа. В следующем примере программы демонстрируются все эти концепции. Она динамически загружает все доступные плагины, не зная, какие плагины есть, за исключением того, что они находятся в подкаталоге «plugins». Затем следует найти символ « Sort» в каждом плагине и ввести его в функцию с сигнатурой func([]int) * []int. Затем для каждого плагина она вызывает функцию сортировки с набором целых чисел и печатает результат.

Заключение

Пакет «Плагин» предоставляет отличную основу для написания сложных программ Go, которые могут динамически загружать плагины по мере необходимости. Интерфейс программирования очень прост и требует подробных знаний об использовании программы на интерфейсе плагина.

Можно создать более продвинутый и удобный фреймворк плагинов поверх пакета «plugin». Надеюсь, он скоро будет перенесен на все платформы. Если вы развертываете свои системы в Linux, рассмотрите возможность использования плагинов, чтобы сделать свои программы более гибкими и расширяемыми.

Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.