SET CGO_ENABLED=0 // 禁用CGO
SET GOOS=linux // 目标平台是linux
SET GOARCH=amd64 // 目标处理器架构是amd64
然后执行go build,得到的就是能够在linux上的可执行文件。
将这个文件上传到linux服务器上,即使Go环境都没有,都可以执行成功。
Windows下编译Mac平台64位可执行程序:
SET CGO_ENABLED=0
SET GOOS=darwin
SET GOARCH=amd64
go build
Mac 下编译 Linux 和 Windows平台 64位 可执行程序:
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build
Linux 下编译 Mac 和 Windows 平台64位可执行程序:
CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build
CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build
python与go性能对比
为了更好的体现出来优化之后的效果,我们大概对比一下两个语言在计算密集情况下的差距。
测试:分别计算一个亿(100000000)的累加模拟大量计算。
Python代码:
import time
defrun(n):sum=0for i inrange(n):sum+= i
print(sum)if __name__ =='__main__':
startTime = time.time()
run(100000000)
endTime = time.time()print("耗时:", endTime - startTime)
耗时5s左右:
Go代码:
package main
import("fmt""time")funcrun(n int){
sum :=0for i :=0; i < n; i++{
sum += i
}
fmt.Println(sum)}funcmain(){var startTime = time.Now()run(100000000)
fmt.Println("耗时:", time.Since(startTime))}
package main
import("C"//C必须导入)//export runfuncrun(n int)int{// 必须通过export 函数名格式的注释申明该函数可以被外部接口
sum :=0for i :=0; i < n; i++{
sum += i
}
fmt.Println("我是Go代码,我跑完了,我的结果是:",sum)return sum
}funcmain(){//main函数中什么都不要写,和包名main要对应}
编译为.so文件供Python调用:
go build -buildmode=c-shared -o s1.so s1.go
格式:go build -buildmode=c-shared -o 输出的.so文件 go源文件
会生成.h文件和.so文件,.so文件供Python调用,如下图所示:
Ptyhon调用so文件
将上述生成的.so文件复制到Python项目的同一级目录。
编写s1.py,依然是计算一个亿,关键部分由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)
package main
import("C"//C必须导入"strconv")//export speakfuncspeak(n int)string{
s :="996好累呀,难得休息一天,好好休息 "+ strconv.Itoa(n)return s
}funcmain(){//main函数中什么都不要写,和包名main要对应}
重复以上步骤,运行s3.py,出现如下错误:
这是因为此时的string不是c语言的对象,而是go语言的对象,修改为如下代码即可:
s2.go代码:
package main
import("C"//C必须导入"strconv")//export speakfuncspeak(n int)*C.char {
s :="996好累呀,难得休息一天,好好休息 "+ strconv.Itoa(n)return C.CString(s)}funcmain(){//main函数中什么都不要写,和包名main要对应}
以上代码申明返回c语言的字符串类型,查看.h文件可以看到:
externchar*speak(GoInt n);
那么s3.py代码只需修改为:
from ctypes import*import time
if __name__ =='__main__':
beginTime = time.time()
s = CDLL("s3.so")# 加载s1.so文件
s.speak.restype = c_char_p
speakStr = s.speak(7).decode("utf-8")print("speak:", speakStr)
endTime = time.time()print("耗时:", endTime - beginTime)
顺利运行。
使用ctypes访问C代码
基本示例
实现两数求和的C代码add.c文件:
#include <stdio.h>
int add_int(int, int);
float add_float(float, float);
int add_int(int num1, int num2){
return num1 + num2;
}
float add_float(float num1, float num2){
return num1 + num2;
}
将C文件编译为.so文件:
#For Linux or windows
gcc -shared -Wl,-soname,adder -o adder.so -fPIC add.c
#For Mac
gcc -shared -Wl,-install_name,adder.so -o adder.so -fPIC add.c
在Python代码中来调用它:
from ctypes import *
adder = CDLL('adder.so')
res_int = adder.add_int(4, 5)
print("Sum of 4 and 5 = " + str(res_int))
add_float = adder.add_float
add_float.restype = c_float
a = c_float(5.5)
b = c_float(4.1)
print("Sum of 5.5 and 4.1 = ", str(add_float(a, b)))
输出:
Sum of 4 and 5 = 9
Sum of 5.5 and 4.1 = 9.600000381469727
#include<math.h>intgcd(int x,int y){int g = y;while(x >0){
g = x;
x = y % x;
y = g;}return g;}intin_mandel(double x0,double y0,int n){double x =0, y =0, xtemp;while(n >0){
xtemp = x * x - y * y + x0;
y =2* x * y + y0;
x = xtemp;
n -=1;if(x * x + y * y >4)return0;}return1;}intdivide(int a,int b,int*remainder){int quot = a / b;*remainder = a % b;return quot;}doubleavg(double*a,int n){int i;double total =0.0;for(i =0; i < n; i++){
total += a[i];}return total / n;}typedefstruct Point {double x, y;} Point;doubledistance(Point *p1, Point *p2){returnhypot(p1->x - p2->x, p1->y - p2->y);}
命令行执行以下代码,编译c:
gcc -shared -o sample.so sample.c
在 sample.so 所在文件相同的目录编写python代码,sample.py文件:
import ctypes
_mod = ctypes.cdll.LoadLibrary('sample.so')# int gcd(int, int)
gcd = _mod.gcd
gcd.argtypes =(ctypes.c_int, ctypes.c_int)
gcd.restype = ctypes.c_int
# int in_mandel(double, double, int)
in_mandel = _mod.in_mandel
in_mandel.argtypes =(ctypes.c_double, ctypes.c_double, ctypes.c_int)
in_mandel.restype = ctypes.c_int
# int divide(int, int, int *)
_divide = _mod.divide
_divide.argtypes =(ctypes.c_int, ctypes.c_int, ctypes.POINTER(ctypes.c_int))
_divide.restype = ctypes.c_int
defdivide(x, y):
rem = ctypes.c_int()
quot = _divide(x, y, rem)return quot, rem.value
# void avg(double *a, int n)# 定义 'double *'参数的类型classDoubleArrayType:deffrom_param(self, param):
typename =type(param).__name__
ifhasattr(self,'from_'+ typename):returngetattr(self,'from_'+ typename)(param)elifisinstance(param, ctypes.Array):return param
else:raise TypeError("Can't convert %s"% typename)# Cast from array.array objectsdeffrom_array(self, param):if param.typecode !='d':raise TypeError('must be an array of doubles')
ptr, _ = param.buffer_info()return ctypes.cast(ptr, ctypes.POINTER(ctypes.c_double))# Cast from lists/tuplesdeffrom_list(self, param):
val =((ctypes.c_double)*len(param))(*param)return val
from_tuple = from_list
# Cast from a numpy arraydeffrom_ndarray(self, param):return param.ctypes.data_as(ctypes.POINTER(ctypes.c_double))
_avg = _mod.avg
_avg.argtypes =(DoubleArrayType(), ctypes.c_int)
_avg.restype = ctypes.c_double
defavg(values):return _avg(values,len(values))# struct Point { }classPoint(ctypes.Structure):
_fields_ =[('x', ctypes.c_double),('y', ctypes.c_double)]# double distance(Point *, Point *)
distance = _mod.distance
distance.argtypes =(ctypes.POINTER(Point), ctypes.POINTER(Point))
distance.restype = ctypes.c_double