我有以下功能:

func checkFiles(path string, excludedPatterns []string) {
    // ...
}

我想知道,由于excludedPatterns从未更改,我应该通过使var全局(而不是每次都将其传递给函数)来优化它,还是Golang已经通过将它们作为写时复制传递来处理呢?

编辑:我想我可以将 slice 作为指针传递,但是我仍然想知道写时复制行为(如果存在)以及通常是否应该担心按值或按指针传递。

最佳答案

从函数名称来看,即使考虑将参数移至全局变量以节省将参数作为参数传递所需的时间/空间,性能也不是那么关键(IO操作(如检查文件)比调用函数慢得多,而将值(value)传递给他们)。

Go中的slice只是小的描述符,类似于带有指向后备数组的指针和2 int s的结构(长度和容量)。不管支持数组有多大,传递 slice 始终是高效的,您甚至不应该考虑将指针传递给它们,除非您当然想修改 slice header 。

Go中的参数始终按值传递,并复制要传递的值。如果传递指针,则将复制并传递指针值。传递 slice 时,将复制并传递 slice 值(这是一个小描述符)-它将指向相同的后备数组(不会被复制)。

同样,如果您需要多次访问函数中的 slice ,则参数通常会带来额外的好处,因为编译器可以进行进一步的优化/缓存,而如果它是全局变量,则必须格外小心。

有关 slice 及其内部的更多信息:Go Slices: usage and internals

如果您想获得准确的性能数字,请进行基准测试!

这里有一些基准测试代码,它显示了两种解决方案之间没有区别(将slice作为参数传递或访问global slice)。将其保存到slices_test.go这样的文件中,并使用go test -bench .运行

package main

import (
    "testing"
)

var gslice = make([]string, 1000)

func global(s string) {
    for i := 0; i < 100; i++ { // Cycle to access slice may times
        _ = s
        _ = gslice // Access global-slice
    }
}

func param(s string, ss []string) {
    for i := 0; i < 100; i++ { // Cycle to access slice may times
        _ = s
        _ = ss // Access parameter-slice
    }
}

func BenchmarkParameter(b *testing.B) {
    for i := 0; i < b.N; i++ {
        param("hi", gslice)
    }
}

func BenchmarkGlobal(b *testing.B) {
    for i := 0; i < b.N; i++ {
        global("hi")
    }
}

输出示例:
testing: warning: no tests to run
PASS
BenchmarkParameter-2    30000000                55.4 ns/op
BenchmarkGlobal-2       30000000                55.1 ns/op
ok      _/V_/workspace/IczaGo/src/play  3.569s

关于go - Golang函数参数是否以写时复制形式传递?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/33995634/

10-16 20:35