Golang与Kotlin性能对比 - 第N个质数计算
Golang与Kotlin性能对比 - 第N个质数计算
我进行了一项Go与Kotlin的性能对比测试,决定比较两者在计算第N个质数时的表现。根据我的测试,我发现平均而言,Go计算任意第N个质数所需的时间大约是Kotlin的两倍。例如,如果Kotlin计算第100个质数需要~250,000ns,那么Go则需要~500,000ns。
顺便提一下,我知道计算第N个质数存在优化方法,例如埃拉托斯特尼筛法,但我最初是在RESTful微服务中使用这两个函数来模拟繁重的计算工作。我在下面贴出了我使用的两个函数。
在这方面,Kotlin是否真的比Go更快?还是我遗漏了什么?
非常感谢
fun simplePrime(primeN : Int) : Int {
var primeI = 0
var currNum = 1
while (primeI < primeN) {
currNum += 1
var isPrime = true
for (i in 2..currNum/2) {
if (num % i == 0) {
isPrime = false
break
}
}
if (isPrime) {
primeI += 1
}
}
return currNum
}
func getNthPrime(num int) int {
primeNum := 0
currNum := 1
for primeNum < num {
currNum++
isPrime := true
for i := 2; i < currNum/2; i++ {
if currNum % i == 0 {
isPrime = false
break
}
}
if isPrime {
primeNum++
}
}
return primeNum
}
更多关于Golang与Kotlin性能对比 - 第N个质数计算的实战教程也可以访问 https://www.itying.com/category-94-b0.html
算法认为4是质数?… 
抱歉,我发布的函数版本不一致。我会更新帖子。
我最初让两个函数都遍历整个数字集合,但后来进行了一些优化以使其更符合实际情况,只是我没有意识到我发布的是 Kotlin 的优化版本,而不是 Go 的。不过,根据我找到的数字和数据,我测试时对两者都使用了“优化”后的函数。
在这种情况下,您需要分享更多关于您实际如何进行基准测试的细节。
顺便提一下,对同一算法在两种不同编程语言中进行有意义的比较可能相当困难。这完全取决于具体测量的是什么、测试函数执行了多少次(例如,CPU缓存是冷启动还是热启动)等因素。
呃,你是在暗示它不是这样吗?
幸好我没有在任何地方使用这段代码
Kotlin 代码和 Go 代码并不相同。在 Go 中,循环条件应该是
for i := 2; i < currNum/2; i++
这样才能与 Kotlin 版本保持一致。经过此修正后,Go 代码的运行时间实际上减少了约 50%,因此我认为 Kotlin 和 Go 的性能大致相当。
除此之外,我建议在两个版本中使用相同的变量名,这样会更便于代码比较。我认为 Kotlin 代码也存在一些拼写错误:变量 num 应该为 currNum。
所以,如果我运行一个 Go 基准测试,每次迭代得到大约 100,000ns。
goos: linux
goarch: amd64
BenchmarkNthPrime-8 10000 104896 ns/op
PASS
如果我使用 Kotlin 基准测试运行 Kotlin 函数,每次迭代得到大约 40,000ns。
我之前进行的原始测试涉及读取从另一台服务器输入的请求,该服务器每秒触发一次查询,然后我计算了所有迭代的平均值。我猜测差异在于测试方法?
无论如何,差异仍然存在。我假设在这种特定场景下,Kotlin 的表现优于 Go。我只是对如此简单/常见的场景存在如此显著的差异感到惊讶。
如果我说错了请纠正我,但 Kotlin 的 Int 大小是 32 位,而 Golang 的版本取决于平台,因此在 64 位平台上你使用的是 64 位整数。 如果你想比较它们,必须使用 int32。 我对两种变体进行了小规模基准测试,始终得到以下结果:
Benchmark_getNthPrime
Benchmark_getNthPrime-16 1 3251722454 ns/op
Benchmark_getNthPrime32
Benchmark_getNthPrime32-16 1 1365153369 ns/op
看起来 int(64 位版本)比使用 int32 慢 2.38 倍。
请告诉我你在你的设置中发现了什么。
BullardLA: 呃,你的意思是它不是这样吗?🤔
只是有一点点啦 😊
我认为这段代码应该会稍微好一点。
package main
import "fmt"
// IsPrime ...
func IsPrime(n int) bool {
switch {
case n == 2:
return true
case n < 2 || n%2 == 0:
return false
default:
for i := 3; i*i <= n; i += 2 {
if n%i == 0 {
return false
}
}
}
return true
}
func getNthPrime(n int) int {
var result int = 2
for {
if IsPrime(result) {
n--
}
if n == 0 {
return result
}
result++
}
}
func main() {
fmt.Println(getNthPrime(100))
}
我在一台私有服务器上运行了对比测试,服务器配置为 Intel XEON-E3-1270-V3-Haswell 3.5GHz 处理器和 2x 4GB Kingston 4GB DDR3 1Rx8 内存。我禁用了交换分区,并运行了数千次迭代的测试。每次迭代之间,我让程序休眠一秒。我通过用 nanoTime 调用来包裹函数并计算时间差来简单地计时,虽然我知道这可能存在缺陷,但无论如何,我认为这无法解释我观察到的差异。测试期间没有运行任何 CPU 密集型后台进程(CPU 空闲率约 100%)。
我的结果:
- 当
n=100时,- Go:每次迭代约 600,000 纳秒
- Kotlin:每次迭代约 300,000 纳秒
- 当
n=1000时- Go:每次迭代约 50,000,000 纳秒
- Kotlin:每次迭代约 25,000,000 纳秒
我进行的其他性能测试表明 Go 的表现优于 Kotlin(例如冒泡排序、字符串转哈希映射),但我主要想知道我是否在某些根本性的地方做错了,或者 Go 是否在某些特定场景(比如这个)中性能表现不佳。
在我的旧笔记本上(配备 Intel® Core™ i5-6200U CPU @ 2.30GHz,且并非空闲状态),使用以下基准测试:
package nthprime
import "testing"
var result int
func getNthPrime(num int) int {
primeNum := 0
currNum := 1
for primeNum < num {
currNum++
isPrime := true
for i := 2; i < currNum / 2; i++ {
if currNum%i == 0 {
isPrime = false
break
}
}
if isPrime {
primeNum++
}
}
return primeNum
}
func BenchmarkNthPrime(b *testing.B) {
var r int
for i := 0; i < b.N; i++ {
r = getNthPrime(100)
}
result = r
}
我得到了以下结果:
$ go test -bench=. .
goos: linux
goarch: amd64
pkg: nthprime
BenchmarkNthPrime-4 10000 151375 ns/op
PASS
ok nthprime 1.532s
根据 cpu.userbenchmark.com 上的 CPU 对比,Intel XEON 的性能要好得多,但我在笔记本电脑上测试得到的每次操作耗时(约 150000 ns/op)仍然更优。


