Есть ли некоторые уроки или практические уроки о том, как писать расширение для Ruby в Go?
Написание расширения Ruby в Go (golang)
Ответ 1
Go 1.5 добавлена поддержка для создания разделяемых библиотек, которые можно вызывать из C (и, следовательно, из Ruby через FFI). Это облегчает процесс, чем в версиях до 1.5 (когда необходимо было написать слой клея C), и теперь можно использовать время выполнения Go, что делает его действительно полезным в реальной жизни (раньше не могли быть выбраны распределения goroutines и памяти, так как они требуют времени выполнения Go, которое не использовалось, если Go не был основной точкой входа).
goFuncs.go:
package main
import "C"
//export GoAdd
func GoAdd(a, b C.int) C.int {
return a + b
}
func main() {} // Required but ignored
Обратите внимание, что комментарий //export GoAdd
требуется для каждой экспортируемой функции; символ после export
заключается в том, как будет экспортирована функция.
goFromRuby.rb:
require 'ffi'
module GoFuncs
extend FFI::Library
ffi_lib './goFuncs.so'
attach_function :GoAdd, [:int, :int], :int
end
puts GoFuncs.GoAdd(41, 1)
Библиотека построена с помощью
go build -buildmode=c-shared -o goFuncs.so goFuncs.go
Запуск Ruby script вызывает:
42
Ответ 2
Обычно я постараюсь дать вам прямой ответ, но комментарии пока показывают, что их может не быть. Итак, мы надеемся, что этот ответ с общим решением и некоторыми другими возможностями будет приемлемым.
Одно общее решение: скомпилируйте языковую программу высокого уровня в библиотеку, которую можно вызывать из C. Заверните, что для Ruby. На данный момент нужно очень внимательно относиться к интеграции. Этот трюк был хорошим клоком для интеграции многих языков в прошлом, как правило, по причинам, связанным с наследием. Дело в том, что я не разработчик Go, и я не знаю, что вы можете скомпилировать Go во что-то вызываемое из C. Перемещение.
Создайте две автономные программы: Ruby и Go. В программах используйте очень эффективный способ передачи данных вперед и назад. Расширение просто установит соединение с программой Go, отправит данные, дождитесь результата и передаст результат обратно в Ruby. Каналом связи может быть OS IPC, сокеты и т.д. Независимо от каждого поддерживаемого. Формат данных может быть чрезвычайно простым, если нет проблем с безопасностью, и вы используете предопределенные форматы сообщений. Это еще больше повышает скорость. Некоторые из моих старых программ использовали XDR для двоичного формата. В наши дни люди, похоже, используют такие вещи, как JSON, протокольные буферы и проводные протоколы в стиле ZeroMQ.
Изменение второго предложения: используйте ZeroMQ! Или что-то подобное. ZeroMQ быстрый, надежный и имеет привязки для обоих языков. Он управляет целым абзацем для вас. Недостатки в том, что он менее гибкий, и он не нуждается в дополнительных материалах.
Сложная часть использования двух процессов и передачи данных между ними - это ограничение скорости. Накладные расходы могут не оправдывать уход из Ruby. Однако Go имеет отличную производительность и concurrency функции, которые могут оправдывать кодирование части приложения в нем по сравнению с языком сценариев, например Ruby. (Возможно, одно из ваших обоснований для вашего вопроса.) Итак, попробуйте каждую из этих стратегий. Если вы получаете рабочую программу, которая также быстрее, используйте ее. В противном случае, придерживайтесь Ruby.
Возможно, менее привлекательный вариант: используйте что-то другое, кроме Go, которое имеет схожие преимущества, позволяет звонить с C и может быть интегрировано. Хотя это не очень популярно, Ада - это возможность. Он долго был сильным в собственном коде, (ограниченный) concurrency, надежность, поддержка низкого уровня, кросс-языковая разработка и IDE (GNAT). Кроме того, Julia - это новый язык для высокопроизводительного технического и параллельного программирования, который может быть скомпилирован в библиотеку, вызываемую с C. У нее есть JIT. Возможно, решение проблемы с Ruby + Go to Ruby + (более подходящий язык) решит проблему?
Ответ 3
Как и в случае Go 1.5, существует новый режим сборки, который сообщает компилятору Go для вывода общей библиотеки и файла заголовка C:
-buildmode c-shared
(Это объясняется более подробно в этом полезном учебнике: http://blog.ralch.com/tutorial/golang-sharing-libraries/)
В новом режиме сборки вам больше не нужно писать слой клея C (как ранее предполагалось в более ранних ответах). После того, как у вас есть разделяемая библиотека и заголовочный файл, вы можете перейти к использованию FFI для вызова общей библиотеки Go (см. Здесь: https://www.amberbit.com/blog/2014/6/12/calling-c-cpp-from-ruby/)