踢馆挑战 Ruby(MRuby) vs Golang 性能对比

前言

大家好我是 Mark24。

今天主要是想聊下一个有趣的发现,MRuby 和 Golang 的巅峰对决。

简单介绍下今天的主角,挑战者 MRuby 是 遵循 Ruby ISO 语法规范的一个实现。M 是 ”embed(嵌入)”的“m”,同时也是 minimalistic(极简的)的“m”,是作者重新设计的一个 Ruby 解释器。

MRuby 是把 Ruby 的开发体验带到嵌入式世界。为了兼容嵌入式的各种苛刻要求。MRuby 的实现相比于 CRuby 添加了大量的改进。

更小的体积 整个语言可以裁剪特性分开构建 软件实时性 节约内存 更好的移植性

由于其可移植性,被设计的尽可能不依赖于系统,相较于 CRuby 不可以独立的打包成二进制。MRuby 的解释器是可以被独立编译的。方便携带。

也因为可移植性,所以在日常的计算机系统中也是可用。

MRuby 由于其体积和性能,常常和 Lua 进行比较。适合嵌入软件系统中来工作。

MRuby 脚手架 Mark24Code/mruby-devkit

MRuby 编译成二进制,还是需要手动做一些事情。

Mark24Code/mruby-devkit

我粗糙的做了一个简单的脚手架,可以工作在 MacOS、Debian Distro Linux 中。

可以方便的进行把 Ruby 编译成二进制可执行文件。

模仿 golang 的 go run

`rake 'run[main.rb]'`

模仿 golang 的 go build

`rake 'build[main.rb]'`

Benchmark

我们简单的通过 斐波那契 数列来进行简单的计算对比。

1. 最简单的递归算法

操作系统使用:macOS 13.6.7

go 使用 go1.22.4 darwin/arm64 mruby 使用 mruby 3.3.0 (2024-02-14)

算法保持一致,代码如下:

// fib.go
package main

import (
	"fmt"
)

func fib(num int) int {
	if num < 2 {
		return num
	} else {
		return fib(num-1) + fib(num-2)
	}
}

func main() {
	fmt.Print(fib(40))
}
# fib.rb
def fib(n)
  if n < 2
    n
  else
    fib(n-2) + fib(n-1)
  end
end

puts fib(40)

日志

# go
time ./fib
102334155./fib  0.37s user 0.01s system 99% cpu 0.382 total

# mruby
102334155
./build/fib  15.30s user 0.05s system 99% cpu 15.357 total
语言 时间(秒/s) 倍率 mruby 0.37 1 golang 15.30 41.35

看到这里估计各位都笑了,在想什么玩意儿,在这里踢馆。

实际上递归其实非常不适合 MRuby。MRuby 对内存做了约束,MRuby 在系统监视器中,一致保持着 1.4M 的内存在运行。它无法很好的展开内存。

我们换一个语法。使用迭代的算法。

# fib2.rb
def fib(n)
  return n if n <= 1

  fib_minus_2 = 0  # F(0)
  fib_minus_1 = 1  # F(1)
  fib_n = nil

  (2..n).each do |i|
    fib_n = fib_minus_1 + fib_minus_2
    fib_minus_2 = fib_minus_1
    fib_minus_1 = fib_n
  end

  fib_n
end

puts fib(80)

// fib2.go
package main

import "fmt"

// fibonacci 函数使用迭代方法计算第 n 项斐波那契数
func fib(n int) int {
	if n <= 1 {
		return n
	}

	fibMinus2 := 0 // F(0)
	fibMinus1 := 1 // F(1)
	fibN := 0

	for i := 2; i <= n; i++ {
		fibN = fibMinus1 + fibMinus2
		fibMinus2, fibMinus1 = fibMinus1, fibN
	}

	return fibN
}

func main() {
	fmt.Printf("%d", fib(80))
}

日志

# mruby
23416728348467685
./build/fib2  0.00s user 0.00s system 75% cpu 0.009 total

# go
23416728348467685./fib2  0.00s user 0.01s system 77% cpu 0.009 total

这样的算法已经难分伯仲。

参考

《关于 mruby 的一切》

文章来源:

Author:Mark24
link:https://mark24code.github.io/ruby/2024/06/06/踢馆挑战MRubyvsGolang性能对比.html