使用Go(golang)编写Ruby扩展

huangapple go评论109阅读模式
英文:

Writing a Ruby extension in Go (golang)

问题

有关如何使用Go编写Ruby扩展的教程或实践课程吗?

英文:

Are there some tutorials or practical lessons on how to write an extension for Ruby in Go?

答案1

得分: 76

Go 1.5增加了对构建可从C调用的共享库的支持(因此可以通过FFI从Ruby调用)。这使得与1.5之前的版本相比,该过程更加简单(以前需要编写C粘合层),并且Go运行时现在可用,使得在实际生活中实际有用(以前无法使用goroutines和内存分配,因为它们需要Go运行时,如果Go不是主入口点,则无法使用)。

英文:

Go 1.5 added support for building shared libraries that are callable from C (and thus from Ruby via FFI). This makes the process easier than in pre-1.5 releases (when it was necessary to write the C glue layer), and the Go runtime is now usable, making this actually useful in real life (goroutines and memory allocations were not possible before, as they require the Go runtime, which was not useable if Go was not the main entry point).

goFuncs.go:

<!-- language: lang-java -->

package main

import &quot;C&quot;

//export GoAdd
func GoAdd(a, b C.int) C.int {
    return a + b
}

func main() {} // Required but ignored

Note that the //export GoAdd comment is required for each exported function; the symbol after export is how the function will be exported.

goFromRuby.rb:

require &#39;ffi&#39;

module GoFuncs
  extend FFI::Library
  ffi_lib &#39;./goFuncs.so&#39;
  attach_function :GoAdd, [:int, :int], :int
end

puts GoFuncs.GoAdd(41, 1)

The library is built with:

<!-- language: lang-sh -->

go build -buildmode=c-shared -o goFuncs.so goFuncs.go

Running the Ruby script produces:

<pre>
42
</pre>

答案2

得分: 11

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

一个通用的解决方案是:将高级语言程序编译成可从C调用的库。然后再为Ruby进行封装。在这一点上,必须非常小心地进行集成。这个技巧过去是将许多语言集成在一起的一个不错的方法,通常是出于遗留原因。问题是,我不是Go开发人员,也不知道你是否可以将Go编译成可从C调用的东西。继续下一个。

创建两个独立的程序:Ruby程序和Go程序。在这些程序中,使用一种非常高效的方法来传递数据。扩展程序只需建立与Go程序的连接,发送数据,等待结果,并将结果传回Ruby。通信通道可以是操作系统的IPC、套接字等,具体取决于各自的支持。如果没有安全问题,并且使用预定义的消息格式,数据格式可以非常简单。这进一步提高了速度。我以前的一些程序使用XDR作为二进制格式。现在,人们似乎使用JSON、Protocol Buffers和ZeroMQ风格的传输协议。

第二个建议的变体:使用ZeroMQ!或者类似的东西。ZeroMQ快速、稳定,并且有两种语言的绑定。它为你管理了上面的整个段落。缺点是它在性能调优方面不太灵活,并且有一些你不需要的额外内容。

使用两个进程并在它们之间传递数据的棘手之处在于速度惩罚。开销可能不值得离开Ruby。然而,Go具有出色的本地性能和并发功能,这可能会使得在其中一部分应用程序中使用它与像Ruby这样的脚本语言进行编码变得合理。(这可能是你提出这个问题的原因之一。)所以,尝试这些策略中的每一个。如果你得到一个工作正常且更快的程序,就使用它。否则,坚持使用Ruby。

也许不太吸引人的选择是:使用除了Go之外的其他具有类似优势、允许从C调用并可以集成的语言。虽然它不太流行,但Ada是一个可能性。它一直在本地代码、(受限的)并发性、可靠性、低级支持、跨语言开发和IDE(GNAT)方面表现出色。此外,Julia是一种新的高性能技术和并行编程语言,可以编译成可从C调用的库。它还有一个JIT。也许将问题陈述从Ruby+Go改为Ruby+(更合适的语言)会解决问题?

英文:

Normally I'd try to give you a straight answer but the comments so far show there might not be one. So, hopefully this answer with a generic solution and some other possibilities will be acceptable.

One generic solution: compile high level language program into library callable from C. Wrap that for Ruby. One has to be extremely careful about integration at this point. This trick was a nice kludge to integrate many languages in the past, usually for legacy reasons. Thing is, I'm not a Go developer and I don't know that you can compile Go into something callable from C. Moving on.

Create two standalone programs: Ruby and Go program. In the programs, use a very efficient way of passing data back and forth. The extension will simply establish a connection to the Go program, send the data, wait for the result, and pass the result back into Ruby. The communication channel might be OS IPC, sockets, etc. Whatever each supports. The data format can be extremely simple if there's no security issues and you're using predefined message formats. That further boosts speed. Some of my older programs used XDR for binary format. These days, people seem to use things like JSON, Protocol Buffers and ZeroMQ style wire protocols.

Variation of second suggestion: use ZeroMQ! Or something similar. ZeroMQ is fast, robust and has bindings for both languages. It manages the whole above paragraph for you. Drawbacks are that it's less flexible wrt performance tuning and has extra stuff you don't need.

The tricky part of using two processes and passing data between them is a speed penalty. The overhead might not justify leaving Ruby. However, Go has great native performance and concurrency features that might justify coding part of an application in it versus a scripting language like Ruby. (Probably one of your justifications for your question.) So, try each of these strategies. If you get a working program that's also faster, use it. Otherwise, stick with Ruby.

Maybe less appealing option: use something other than Go that has similar advantages, allows call from C, and can be integrated. Althought it's not very popular, Ada is a possibility. It's long been strong in native code, (restricted) concurrency, reliability, low-level support, cross-language development and IDE (GNAT). Also, Julia is a new language for high performance technical and parallel programming that can be compiled into a library callable from C. It has a JIT too. Maybe changing problem statement from Ruby+Go to Ruby+(more suitable language) will solve the problem?

答案3

得分: 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/)

英文:

As of Go 1.5, there's a new build mode that tells the Go compiler to output a shared library and a C header file:

-buildmode c-shared

(This is explained in more detail in this helpful tutorial: http://blog.ralch.com/tutorial/golang-sharing-libraries/)

With the new build mode, you no longer have to write a C glue layer yourself (as previously suggested in earlier responses). Once you have the shared-library and the header file, you can proceed to use FFI to call the Go-created shared library (example here: https://www.amberbit.com/blog/2014/6/12/calling-c-cpp-from-ruby/)

huangapple
  • 本文由 发表于 2013年4月8日 21:12:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/15879993.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定