40

是否有一些关于如何在 Go 中为 Ruby 编写扩展的教程或实践课程?

4

3 回答 3

76

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 脚本会产生:

42
于 2013-04-22T02:51:38.113 回答
11

通常我会尽量给你一个直接的答案,但到目前为止的评论显示可能没有答案。因此,希望这个带有通用解决方案的答案和其他一些可能性是可以接受的。

一种通用解决方案:将高级语言程序编译为可从 C 调用的库。为 Ruby 包装它。在这一点上,人们必须非常小心地进行整合。这个技巧是过去集成许多语言的一个很好的组合,通常是出于遗留原因。问题是,我不是 Go 开发人员,我不知道你可以将 Go 编译成可以从 C 调用的东西。继续前进。

创建两个独立程序:Ruby 和 Go 程序。在程序中,使用一种非常有效的方式来回传递数据。该扩展将简单地建立与 Go 程序的连接、发送数据、等待结果并将结果传递回 Ruby。通信通道可能是 OS IPC、套接字等。无论它们都支持什么。如果没有安全问题并且您使用的是预定义的消息格式,则数据格式可以非常简单。这进一步提高了速度。我的一些旧程序将 XDR 用于二进制格式。如今,人们似乎使用 JSON、Protocol Buffers 和 ZeroMQ 风格的有线协议之类的东西。

第二个建议的变化:使用 ZeroMQ!或类似的东西。ZeroMQ 快速、健壮并且具有两种语言的绑定。它为您管理上述整个段落。缺点是它在性能调整方面不太灵活,并且有你不需要的额外东西。

使用两个进程并在它们之间传递数据的棘手部分是速度损失。开销可能不足以成为离开 Ruby 的理由。但是,Go 具有出色的本机性能和并发特性,这可能证明在其中编写应用程序的一部分而不是像 Ruby 这样的脚本语言是合理的。(可能是您提出问题的理由之一。)因此,请尝试每种策略。如果您获得的工作程序也更快,请使用它。否则,请坚持使用 Ruby。

可能不太吸引人的选项:使用 Go 以外的其他具有类似优势的东西,允许从 C 调用,并且可以集成。尽管它不是很受欢迎,但 Ada 是一种可能性。它在本机代码、(受限)并发性、可靠性、低级支持、跨语言开发和 IDE (GNAT) 方面一直很强大。此外,Julia 是一种用于高性能技术和并行编程的新语言,可以编译成可从 C 调用的库。它也有 JIT。也许将问题陈述从 Ruby+Go 更改为 Ruby+(更合适的语言)会解决问题?

于 2013-04-17T22:56:52.340 回答
4

从 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/ )

于 2015-09-15T21:18:27.327 回答