Комментарии 8
Какой оверхед получается по сравнению с вызовом функций из библиотеки на C, например? Вы ведь фактически через 2 FFI прослойки проходите в этом случае.
В cgo комментарии имеют значение (да, это странно)
В Go, вы хотели сказать. Есть ряд специальных комментариев, которые выполняют роль подсказок компилятору, своего рода препроцессор. Это не особенность именно cgo. Практически всё, что начинается с ^//[a-z]+:?
будет с большой вероятностью являться комментарием, который имеет значение.
Странно как раз, когда наоборот. Документацию, пояснения, обычно пишут либо в многострочных комментариях, либо с пробелом после //
Данная команда создаст файл lib.a (который и представляет из себя динамическую c библиотеку)
Расширение .a
имеют как раз статические библиотеки (в UNIX системах), динамические — .dll
, .so
, .dylib
в зависимости от ОС. То что вы скомпилировали хоть и будет динамической библиотекой, но это нетипичное именование и определённо вызовет непонимание.
фактически через 2 FFI прослойки проходите в этом случае.
Мне казалось, что в том то и фишка. что особых прослоек и нет, так как оверхед только приведение типов, а они, как правило, работают куда меньше по времени, чем те задачи, которые выносят через FFI
Это, вообще говоря, не совсем так.
Во-первых, вызов функции через FFI всё-таки не совсем бесплатный. Пока в библиотеке тяжёлые функции, это в принципе не проблема, тут вы правы. Но с одной стороны нужно из безопасного рантайма Dart подготовить всё для передачи в C, а с другой из C подготовить в безопасный рантайм Go и наоборот при возврате значений.
Во-вторых, преобразование типов это сама по себе достаточно нетривиальная задача. Недостаточно просто передать данные в сыром виде, т.к. внутреннее представление разных типов существенно отличается и в Dart, и в Go, и в C.
Например, в обычном коде ни в Go, ни в Dart вы не встретите строку в виде C-строки (как у вас в примере).
В Go строки представляют собой структуру с указателем на массив и длиной строки в нём, когда как C-строка это char *
, который оканчивается символом \0
. Соответственно, как минимум, придётся дополнительно аллоцировать для этого память, что и делает C.CString
. Это ещё и усугубляется тем, что Go жёстко разделяет области памяти между shared-c кодом и кодом Go.
При этом, в Go строка представлена последовательностью символов UTF-8. Но в Dart класс String является набором символов UTF-16. Поэтому, при передаче такого массива придётся ещё раз выделить память уже на стороне Dart, к тому выполнив преобразование кодировки.
Это не проблема именно FFI, но сопутствующий недостаток, которого избежать достаточно трудно. Практически для всех типов, которые не являются примитивными — вроде чисел различной размерности и их массивов (фиксированной длины) — будет происходить конверсия (а не просто приведение). Не важно, вручную или автоматически. А если это происходит часто и/или объекты немаленькие — это может занимать времени значительно больше, чем вы ожидаете.
Я большой поклонник Го, но очень настоятельно не рекомендую писать на Го shared library: рантайм Го может конфликтовать с рантаймом вызывающего языка (если конкретно - руби в моем случае) при увеличении стэка горутины. Возникает падение связанное с повреждением/порчей памяти.
Данная проблема известна довольно давно, но поскольку данное направление для разработчиков языка не является приоритетным - уже несколько лет остаётся не решенным. Мне не хватает времени для погружения в недра компилятора и создания соответствующего PR. Возможно кто-то, кому это критично сможет выделить ресурсы.
Если нужно вынести вычисления во что-то быстрое, то я бы порекомендовал использовать любые механизмы IPC (Unix sockets, напрямую stdin/stdout pipes, etc) и запускать модуль как отдельный подпроцесс. Или использовать языки с фиксированным стэком. В идеале вообще без рантайма. В крайнем случае - не использовать горутины в shared library.
Dart FFI для вызова Go кода из языка Dart.
А какие практические цели? Если вы пишите, что о некоторых возможностях типа сборщика мусора нужно забыть. Что это значит? можно ли так забиндить, например, готовые библиотеки?
github.com/thoas/picfit
Это значит, что автор плохо прочитал документацию, либо сформулировал плохо.
Для объектов, аллоцированных в куче cgo, естественно, сборщик мусора работать не будет. Но для обычных Go объектов ничего не меняется. Рантайм никуда не делся, сборщик мусора так же все будет нормально собирать, что находится в пределах кучи, которую выделяет Go.
Я для этого и использовал fii (мне очень понравилось стандартная криптографическая библиотека на go, там много функционала представленного в простой и понятной форме).
Если конкретно — я вызывал алгоритмы связанные с Blake2b, rsa и rsassa-pss, тк данных реализаций не было (в сочетании и удобной форме) в готовом виде на языке Dart.
Вызов кода Go из Dart с использованием cgo и Dart FFI на простом примере