Golang移动端代码执行速度优化探讨

Golang移动端代码执行速度优化探讨 我正在使用 GoMobile 来调整图像大小和裁剪图像。 我注意到它运行得太慢了。

Golang PC 端:1.1 秒 Android 上的 Gomobile:15.8 秒 Android 原生:300 毫秒

这是因为 Go 和 Gomobile 没有使用 GPU 硬件加速吗?而移动端原生使用了?

我的代码:

func TestCrop() {

	start := time.Now()
	str := OnInputImage()
	res := base64.NewDecoder(base64.StdEncoding, strings.NewReader(str))


	jpgI, _ := jpeg.Decode(res)
	dest := image.NewRGBA(image.Rect(0, 0, jpgI.Bounds().Dx(), jpgI.Bounds().Dy()))
	gc := draw2dimg.NewGraphicContext(dest)

	gc.SetStrokeColor(color.RGBA{0x00, 0x00, 0x00, 0x00})
	gc.SetLineWidth(1)
	gc.BeginPath()                                                               
	gc.MoveTo(float64(jpgI.Bounds().Dx())*0.24, float64(jpgI.Bounds().Dy())*0.42) 
	gc.LineTo(float64(jpgI.Bounds().Dx())*0.71, float64(jpgI.Bounds().Dy())*0.32)
	gc.LineTo(float64(jpgI.Bounds().Dx())*0.74, float64(jpgI.Bounds().Dy())*0.58)
	gc.LineTo(float64(jpgI.Bounds().Dx())*0.21, float64(jpgI.Bounds().Dy())*0.63)
	gc.Close()
	gc.FillStroke()
	fmt.Println(" crop time 1 :", time.Since(start))

	draw.DrawMask(dest, dest.Bounds(), jpgI, image.Point{0, 0}, dest, image.Point{0, 0}, draw.Src)

	buf := new(bytes.Buffer)
	err := jpeg.Encode(buf, dest, nil)
	if err != nil {

		fmt.Println(" err=:", err)
	}


	fmt.Println(" crop time2 :", time.Since(start))
}

更多关于Golang移动端代码执行速度优化探讨的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于Golang移动端代码执行速度优化探讨的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


你的性能问题确实很可能与硬件加速有关。GoMobile 目前主要使用 CPU 进行图像处理,而 Android 原生代码通常会利用 GPU 进行硬件加速。以下是几个优化方案:

1. 使用原生图像处理库

import "golang.org/x/image/draw"

func OptimizedCrop() {
    start := time.Now()
    
    // 使用更快的图像缩放算法
    src, _ := jpeg.Decode(res)
    
    // 创建目标图像
    dst := image.NewRGBA(image.Rect(0, 0, src.Bounds().Dx(), src.Bounds().Dy()))
    
    // 使用 ApproxBiLinear 或 CatmullRom 进行高质量缩放
    draw.ApproxBiLinear.Scale(dst, dst.Bounds(), src, src.Bounds(), draw.Over, nil)
    
    // 手动实现裁剪逻辑,避免 draw2d 的开销
    cropRect := image.Rect(
        int(float64(dst.Bounds().Dx())*0.24),
        int(float64(dst.Bounds().Dy())*0.42),
        int(float64(dst.Bounds().Dx())*0.71),
        int(float64(dst.Bounds().Dy())*0.63),
    )
    
    cropped := image.NewRGBA(cropRect)
    draw.Draw(cropped, cropped.Bounds(), dst, cropRect.Min, draw.Src)
    
    fmt.Println("优化后时间:", time.Since(start))
}

2. 并行处理优化

func ParallelProcess(img image.Image) image.Image {
    bounds := img.Bounds()
    dst := image.NewRGBA(bounds)
    
    // 使用 goroutine 并行处理图像块
    const numWorkers = 4
    var wg sync.WaitGroup
    heightPerWorker := bounds.Dy() / numWorkers
    
    for i := 0; i < numWorkers; i++ {
        wg.Add(1)
        go func(workerID int) {
            defer wg.Done()
            
            yStart := workerID * heightPerWorker
            yEnd := yStart + heightPerWorker
            if workerID == numWorkers-1 {
                yEnd = bounds.Dy()
            }
            
            for y := yStart; y < yEnd; y++ {
                for x := bounds.Min.X; x < bounds.Max.X; x++ {
                    // 处理每个像素
                    dst.Set(x, y, img.At(x, y))
                }
            }
        }(i)
    }
    
    wg.Wait()
    return dst
}

3. 使用 SIMD 优化(通过汇编)

// 使用 golang.org/x/sys/cpu 检测 SIMD 支持
import "golang.org/x/sys/cpu"

func SIMDOptimizedProcess(src []byte, dst []byte) {
    if cpu.X86.HasAVX2 {
        // 使用 AVX2 优化的处理
        processAVX2(src, dst)
    } else if cpu.X86.HasSSE2 {
        // 使用 SSE2 优化的处理
        processSSE2(src, dst)
    } else {
        // 回退到普通处理
        processScalar(src, dst)
    }
}

4. 内存池优化

var bufferPool = sync.Pool{
    New: func() interface{} {
        return make([]byte, 0, 1024*1024) // 预分配 1MB
    },
}

func ProcessWithPool() {
    buf := bufferPool.Get().([]byte)
    defer bufferPool.Put(buf[:0]) // 重置长度
    
    // 使用 buf 进行图像处理
    // ...
}

5. 考虑混合方案

如果性能要求极高,可以考虑:

// 通过 JNI 调用 Android 原生图像处理
// #cgo LDFLAGS: -landroid -llog
// #include <jni.h>
import "C"

func NativeAndroidProcessing(data []byte) []byte {
    // 调用 Android 原生图像处理库
    // 这需要编写 JNI 桥接代码
}

主要性能瓶颈确实在于 draw2dimg 库和缺乏 GPU 加速。建议:

  1. 替换 draw2dimg 为 golang.org/x/image/draw
  2. 对于复杂图形操作,考虑使用更轻量的库
  3. 如果必须使用 GPU,需要通过 JNI 调用 Android 原生图形 API
回到顶部