1. 前言

大部分小伙伴们应该都知道Python是一个生产力很高的语言,它可以以最高的效率完成最多的事,但Python的性能一直是我们诟病的一个问题,尤其是一个大锁 GIL。

可能有的小伙伴听说过 Python + C\C++,用 C\C++ 重写 Python 计算密集的地方,来提高性能

当然, 这是一种很好的解决办法,但是我们知道 C\C++ 是有一些学习成本,有没有再更好的解决方案呢?

当然了,现在我们大部分程序都是( IO )网络密集型程序,Python 足以胜任,但是如果说我们已经存在的项目或者想要开发的项目中,存在有计算密集型的程序场景,我们该怎么办呢?

 

2. 调用 Golang

后来有幸接触到了 Golang,使用了一端时间小编就在想,Python 要是能调用 Go 代码就好了,实在是不想学习 C\C++,毕竟 C\C++ 的指针和自己释放内存还是比较有门槛的,Go 就很方便了,垃圾自动回收,省的内存泄漏还有天生高并发等优势

经过不断的查阅了一些资料,踩了一些坑,功夫不负有心人,终于找到了合适的办法,在此分享给大家。

目 前最广泛的 Python 解释器是 CPython,Python 正好留出来有可以调用 C\C++ 代码的模块,Go 经过一些方法,也是可以编译成类似 Python 可调用的 C\C++ 的文件

3. 测试环境

系统 : windows

Python解释器:Python 3.7.6(64位)

Go编译器:Go 1.14(64位)

4. 性能对比

为了更好的体现出来优化之后的效果,我们大概对比一下两个语言在计算密集情况下的差距。

测试: 分别计算一个亿(100000000)的累加模拟大量计算。

1、Python代码

import time

def run(n):
    sum = 0
    for i in range(n):
        sum += i
    print(sum)


if __name__ == '__main__':
    startTime = time.time()
    run(100000000)
    endTime = time.time()
    print("耗时:", endTime - startTime)

可以看到耗时:10s 左右,如下图所示:

结合 Golang来提高 Python 的计算性能

2、Golang 代码

package main

import (
  "fmt"
  "time"
)

func run(n int) {
  sum := 0
  for i := 0; i < n; i++ {
    sum += i
  }
  fmt.Println(sum)
}
func main() {
  var startTime = time.Now()
  run(100000000)
  fmt.Println("耗时:", time.Since(startTime))
}

可以看到耗时:200ms 左右,如下图所示:

结合 Golang来提高 Python 的计算性能

3、测试结论

我们可以看到,在计算方面,Python 和 Go 是有很大的差距的,如果计算这一块能放在 Go 上就好了

5. Golang 编译为 so 库

1、Go 代码

功能:接收传入的值进行累加,并且返回最终的累加值。

package main

import (
  "C" //C必须导入
)

//export run
func run(n int) int{
  /*
    必须要export 函数名
    //是注释的意思,相当于Python中的 #
    我也是第一次见注释还有作用,黑人三问好???
    固定写法
  */
  sum := 0
  for i := 0; i < n; i++ {
    sum += i
  }
    fmt.Println("我是Go代码,我跑完了,我的结果是:",sum)
  return sum
}

func main() {
  //main函数中什么都不要写,和包名main要对应
}

2、编译为 .so 文件供 Python 调用

命令如下:

go build -buildmode=c-shared -o 输出的.so文件 go源文件

例如:

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

会生成 .h 文件和 .so 文件,.so 文件供 Python 调用,如下图所示:

结合 Golang来提高 Python 的计算性能

3、Python 调用 so 文件

将上述生成的 .so 文件复制到 Python 项目的同一级目录

结合 Golang来提高 Python 的计算性能

4、Python 代码 

依然是计算一个亿,关键部分由 Go 生成的 .so 执行

from ctypes import *
import time


if __name__ == '__main__':
    startTime = time.time()

    s = CDLL("s1.so")  # 加载s1.so文件
    result = s.run(100000000)  # 调用Go生成的.so文件里面的run函数
    print("result:", result)

    endTime = time.time()
    print("耗时:", endTime - startTime)

可以看到 耗时: 0.11s 左右,如下图所示

结合 Golang来提高 Python 的计算性能

5、为什么计算的耗时时间不一致,难道是计算错了???

我们可以看到,虽然速度很快,但是 Python 在调用 Go 生成的 .so 文件之后,拿到的返回值竟然是错的,但是在 Go 中打印的确实对的,这是为什么呢???

不要慌,问题不大! 我们来计算一次稍微小一点的,上个100w的。

结合 Golang来提高 Python 的计算性能

额,怎么还是错误。

6、我们再来计算更小一些的数,以 10023 为例,一个不零不整的数值

结合 Golang来提高 Python 的计算性能

这次可以看到,结果是对的。但是 100w+ 结果为什么会是错的呢???

我们在上述可以知道,.so 文件计算的结果却是正确的,可能是在 python 接收的时候转换的时候错了,不过别捉急,本章已经有点长了,在下章一定会把这个坑解决的,敬请期待~

6. 最后

也许 Python+Go 提高关键地方性能和 Python + C\C++ 相比不是最好的,但是小编认为该方法却是最省心的,毕竟 C\C++ 的门槛是比较高的。 

不过话说回来,目前这个性能确实可能也够用了,毕竟 Python+Go 比 Python+C\C++ 的效率可能要高上几倍不止

用最少的时间撸完最多的代码,加最少的班,人生苦短,我们用 Python ~~

相关文章:

  • 2021-11-29
  • 2021-06-17
  • 2021-12-30
  • 2021-12-16
  • 2021-11-12
  • 2021-11-29
猜你喜欢
  • 2021-08-31
  • 2021-11-14
  • 2021-05-12
  • 2021-06-25
  • 2021-12-15
  • 2021-10-01
  • 2021-05-01
相关资源
相似解决方案