龙空技术网

不要诟病Python慢了,调用Go或者C提速吧

南站往南 1200

前言:

今天大家对“动态加载c语言”大概比较重视,兄弟们都想要剖析一些“动态加载c语言”的相关知识。那么小编也在网摘上网罗了一些有关“动态加载c语言””的相关文章,希望大家能喜欢,小伙伴们一起来了解一下吧!

很多人都说Python慢,Python在计算密集型场景确实慢,一般建议由其他语言实现。

那么什么场景下是计算密集型?下面举一个简单的例子来看看。

本文不做严格的性能比对,用我个人的MacBook pro来测试。

下图是某一个场景下Python和Go不严格的性能测试结果,看每秒处理速度提升接近200倍,平均处理时间从22ms提升到不足0.15ms,相信在一般的业务中0.15ms的引入时延基本上不会影响到正常业务的进行了。

Python计算22ms左右

img是一个灰度图的矩阵,每个像素是0~255的1个值,这个值映射到tmp_map中有一个对应的值。

下面的函数就是求这个图像最大的10个点映射值的平均值

    def handle_temp(self, img: np.ndarray, img_w, img_h, tmp_map: array.array):        max_temp_list = [0 for i in range(10)]        for i in range(0, img_w):            for j in range(0, img_h):                v = img[i*img_h+j]                tmp = tmp_map[v]                for i in range(10):                    if max_temp_list[i] >= tmp:                        break                    if i > 0:                        max_temp_list[i-1] = max_temp_list[i]                    max_temp_list[i] = tmp        return sum(max_temp_list)/10

我们做循环处理反复计算这个结果,10秒钟统计一次,统计结果展示如下,看到每次计算了大约11万的点,python平均22ms左右的时间。

handle 440, cost:10.008, avg:43.96 个/秒, avg cost:22.746ms,  point:110592handle 427, cost:10.014, avg:42.64 个/秒, avg cost:23.452ms,  point:110592handle 451, cost:10.005, avg:45.08 个/秒, avg cost:22.185ms,  point:110592handle 425, cost:10.006, avg:42.47 个/秒, avg cost:23.544ms,  point:110592handle 465, cost:10.017, avg:46.42 个/秒, avg cost:21.542ms,  point:110592handle 459, cost:10.013, avg:45.84 个/秒, avg cost:21.815ms,  point:110592handle 423, cost:10.018, avg:42.23 个/秒, avg cost:23.682ms,  point:110592handle 448, cost:10.004, avg:44.78 个/秒, avg cost:22.330ms,  point:110592handle 441, cost:10.017, avg:44.02 个/秒, avg cost:22.715ms,  point:110592handle 443, cost:10.016, avg:44.23 个/秒, avg cost:22.609ms,  point:110592

Python调用go性能提升近200倍

使用go来重写计算部分,逻辑差不多,实现也比较简单

//遍历横坐标for iX := x; iX < x+w; iX++ {    for iY := y; iY < y+h; iY++ {        cur := iX*imgH + iY        //fmt.Println(iX, iY, cur)        //获取像素值        rgb := imgArray[cur]        // 范围保护        if rgb < 0 || rgb > 255 {            continue        }        for idx := 0; idx < 10; idx++ {            // 从小到大比较之前的温度值            if maxTempArray[idx] < tmpArray[rgb] {                if idx > 0 {                    // 当前位置的往前移动                    maxTempArray[idx-1] = maxTempArray[idx]                }                //最新上top10的温度替换, 如果是索引0的,直接替换上榜                maxTempArray[idx] = tmpArray[rgb]            } else {                //跳出                break            }        }    }}//计算总数sumTemp := 0for idx := 0; idx < 10; idx++ {    sumTemp += maxTempArray[idx]}

同样的进行性能测试,每次计算不到0.2ms,相对于直接使用Python计算,性能上有接近200倍的提升

handle 76718, cost:10.000, avg:7671.70 个/秒, avg cost:0.130ms, point:110592handle 77479, cost:10.000, avg:7747.85 个/秒, avg cost:0.129ms, point:110592handle 76495, cost:10.000, avg:7649.50 个/秒, avg cost:0.131ms, point:110592handle 76349, cost:10.000, avg:7634.83 个/秒, avg cost:0.131ms, point:110592handle 76104, cost:10.000, avg:7610.30 个/秒, avg cost:0.131ms, point:110592handle 76266, cost:10.000, avg:7626.53 个/秒, avg cost:0.131ms, point:110592handle 74852, cost:10.000, avg:7485.14 个/秒, avg cost:0.134ms, point:110592handle 75608, cost:10.000, avg:7560.78 个/秒, avg cost:0.132ms, point:110592handle 74283, cost:10.000, avg:7428.22 个/秒, avg cost:0.135ms, point:110592handle 73874, cost:10.000, avg:7387.31 个/秒, avg cost:0.135ms, point:110592handle 74223, cost:10.000, avg:7422.21 个/秒, avg cost:0.135ms, point:110592handle 69534, cost:10.000, avg:6953.33 个/秒, avg cost:0.144ms, point:110592

Python调用go的实现

得益于go的强大,Python调用go跟调用C的dll一样,有朋友问为啥不直接用C来实现dll,主要是go编译发布方便,代码写起来也稍微简单些。

下面是Python调用范例

# dll加载img_handle = CDLL(dll_path)# getMaxTemp(img *uint8, imgW int, imgH int, x int, y int, w int, h int, tempIdx *int16) intimg_handle.argtypes = [POINTER(c_uint8), c_int, c_int, c_int, c_int, c_int, c_int, POINTER(c_int16)]# 返回类型声明img_handle.restype = c_int# 计算max_temp = img_handle.getMaxTemp(ndarray.ctypes.data_as(POINTER(c_uint8)),                                         img_w, img_h, 0, 0, img_w, img_h,                                         ((POINTER(c_uint32) * 256).from_buffer(tempIdx)))# getMaxTemp放到了1000倍,还原;再除以10还原到原始温度值return max_temp/1000/10

go函数的声明方式,特别注意有几个点

①需要import "C"

②函数名前面需要备注export 函数名,特殊的语法糖

③编译的时候需要注意buildmode属性设置,如下

go build -o detect_img -buildmode=c-shared detect_img.go

package mainimport (    "C"    "fmt"    "unsafe")// 支持最大的宽度和高度const (    MAX_IMG_WIDTH  = 8000    MAX_IMG_HEIGHT = 6000    TEMP_IDX_SIZE  = 256)//export getMaxTempfunc getMaxTemp(img *uint8, imgW int, imgH int, x int, y int, w int, h int, tempIdx *uint32) int {

标签: #动态加载c语言