我是才从C++迁移到go语言来的,因此对内存管理和变量生存期这块特别敏感,对效率也相对要求比较苛刻,开始使用过程中有很多困惑,可能还不习惯用GO吧,请高手指点:
1、有关channel的效率问题,比如我定义一个channel变量,ch1:=make(chan string) ,在goroutinue中向chan中读取(c<-ch1)和写入(ch1<-c)操作是否会产生string的复制代价,同理如果chan是一个很大的结构体,结构体里有大数组等,如果每次写入和读取chan都要复制一次数据,相当于c语言的memcpy,那么不仅会占用栈空间,而且造成程序效率底下。如果chan都定义为指针是否可以解决这个问题?是否会引入新的问题?
2、还是chan的问题,是否所有chan不用时都要执行关闭操作?如不关闭chan,垃圾回收是否会起作用?是否会造成内存泄露,资源是否一直占用?
假如有如下程序,在map中定义了插入了一个含有很多chan的结构体变量的元素,当删除这个元素时(没有显示关闭这些chan),是否会引发上述问题?
type MySTC struct {
ch1 chan [1000]int
ch2 chan string
ch3 chan []byte
a int
}
func main() {
m1 := make(map[int]MySTC)
m1[0] = MySTC{
ch1: make(chan [1000]int, 100),
ch2: make(chan string),
ch3: make(chan []byte),
a: 0,
}
fmt.Println(m1)
dosomething(m1)
delete(m1, 0)
for{
time.Sleep(time.second*100)
}
}
3、map的遍历问题,很欣慰的是go提供了range的变量操作,但是我想在遍历的时候为所有map中的数据加上一个'x',好像只能这样:
func test_map() {
m1 := make(map[int]string)
for i := 0; i < 5; i++ {
m1[i] = strconv.Itoa(i)
}
fmt.Println(m1)
for k, v := range m1 {
//v += "x" ,由于v是元素的copy,因此修改v不能更改相应的元素值
m1[k] += "x"
}
fmt.Println(m1)
}
感觉很不友好,既然我已经获取了m1[k]的值,可是我要修改它却要再一次调用m1[k],这不是又一次查询吗,很明显降低效率啊,我试了用&v报编译错误,这个问题在C++中可以把迭代器赋给一个引用变量来实现对容器元素的修改,可在Go语言中该怎么做呢?
更多评论
1.会复制的,但go的栈会建立内存池,重复的栈内存申请会从内存池中进行分配,避免从系统申请提高效率。但总的内存使用量会较大,可用使用指针定义避免复制,但会引入新的问题,如果chan 数组很大的话,大量指针对象会导致gc效率过低的问题,所以不建议在数组或MAP中使用指针
2.gc 不用的chan 会有gc 进行内存回收,不会有问题。
3.go 里没有 iterator,你代码列出的这个应用场景相比c 有性能耗损。在map value里放指针可以解决这个问题,但会引入新的问题就是gc效率问题。
最后 : go 不是 c 相比 c语言是有些缺点的,比如不支持手动gc 导致你提到的问题 1 和3 。
总体来说有点内存换效率的意思。
如果go的优点不足以吸引你,那c 还是最佳选择。
#2