我正在做一个测试:比较CGO和纯GO函数各运行1亿次的执行时间.与Golang函数相比,CGO函数需要更长的时间,我对此结果感到困惑.我的测试代码是:

package main

import (
    "fmt"
    "time"
)

/*
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void show() {

}

*/
// #cgo LDFLAGS: -lstdc++
import "C"

//import "fmt"

func show() {

}

func main() {
    now := time.Now()
    for i := 0; i < 100000000; i = i + 1 {
        C.show()
    }
    end_time := time.Now()

    var dur_time time.Duration = end_time.Sub(now)
    var elapsed_min float64 = dur_time.Minutes()
    var elapsed_sec float64 = dur_time.Seconds()
    var elapsed_nano int64 = dur_time.Nanoseconds()
    fmt.Printf("cgo show function elasped %f minutes or \nelapsed %f seconds or \nelapsed %d nanoseconds\n",
        elapsed_min, elapsed_sec, elapsed_nano)

    now = time.Now()
    for i := 0; i < 100000000; i = i + 1 {
        show()
    }
    end_time = time.Now()

    dur_time = end_time.Sub(now)
    elapsed_min = dur_time.Minutes()
    elapsed_sec = dur_time.Seconds()
    elapsed_nano = dur_time.Nanoseconds()
    fmt.Printf("go show function elasped %f minutes or \nelapsed %f seconds or \nelapsed %d nanoseconds\n",
        elapsed_min, elapsed_sec, elapsed_nano)

    var input string
    fmt.Scanln(&input)
}

结果是:

cgo show function elasped 0.368096 minutes or 
elapsed 22.085756 seconds or 
elapsed 22085755775 nanoseconds

go show function elasped 0.000654 minutes or 
elapsed 0.039257 seconds or 
elapsed 39257120 nanoseconds

结果表明,调用C函数比调用GO函数慢.我的测试代码有问题吗?

我的系统是:Mac OS X 10.9.4(13E28)

推荐答案

正如您已经发现的,通过CGO调用C/C++代码的开销相当高.因此,一般来说,您最好尽量减少CGO调用的数量.对于上面的例子,与其在循环中重复调用CGO函数,不如将循环下移到C.

Go运行时如何设置线程有很多方面可能会打破许多C代码的期望:

  1. Goroutine在相对较小的堆栈上运行,通过分段堆栈(旧版本)或复制(新版本)处理堆栈增长.
  2. Go运行时创建的线程可能无法与libpthread的线程本地存储实现正确交互.
  3. Go运行时的UNIX信号处理程序可能会干扰传统的C或C++代码.
  4. Go重用OS线程来运行多个Goroutine.如果C代码调用了阻塞系统调用或以其他方式垄断了线程,则可能会对其他goroutine造成损害.

出于这些原因,CGO Select 了在使用传统堆栈设置的单独线程中运行C代码的安全方法.

如果您来自Python这样的语言,在这些语言中,通过重写C代码热点来加速程序的做法并不少见,您会失望的.但与此同时,等价的C代码和GO代码在性能上的差距要小得多.

一般来说,我保留CGo用于与现有库接口,可能是使用小型C包装函数,这样可以减少从Go进行调用的次数.

Go相关问答推荐

Go编译器标志-修剪路径不完全工作

从Kafka到Clickhouse的实时消费数据

将类型定义为泛型类型实例化

创建服务时云运行触发器执行失败

无法使用Segentio;S Kafka-Go连接到融合的Kafka

按位移计算结果中的差异

如何将Golang测试用例的测试覆盖率值与特定阈值进行比较

下载和合并时输出文件已损坏

Opensearch 错误 ping 弹性服务器:由未知权威签署的 x509 证书

在 Cloud Run 中找不到默认凭据

获取 nil 指针类型的 reflect.Value

我突然无法再将我的 GoLang 应用程序部署到 Google AppEngine

regex.ReplaceAll 但如果替换则添加相同数量的字符

当函数返回一个函数时,为什么 Go 泛型会失败?

如何在 Docker 容器中使用私有存储库进行身份验证

NaN 是 golang 中的可比类型吗?

如何使用 math/big 对 bigInt 进行取模?

在 Golang 中获取谷歌云服务帐户的访问令牌?

go routine 和接收错误或成功的通道

Scanner.Buffer - 最大值对自定义拆分没有影响?