golang开发博客的一些经验总结

国庆节时,用大约9天时间借助golang重写编写了博客系统的前台部分,由于系统的特殊性,这部分完成后只能说完成了整套系统1/3的功能。十一回来后,又用了大约10天时间,每天写一点,完成了系统余下的两部分内容。由于是第一次用golang开发服务器内容,所以踩得坑不少,这里做一个总结。

函数传值问题

这个问题不算难,一开始看文档的时候已经注意到了,但没太在意。因为很多逻辑代码都是照搬旧版Nodejs版本来写的,所以就更加忽略了这个问题。知道本地命令操作时间略长,我才感觉不对劲。

举一个简单的例子:

package main

import (
	"fmt"
	"time"
)

func main() {
	_abc()
}

func _abc() {
	fmt.Println("start")
	starttime := time.Now()
	var data Tt
	for i := 0; i < 10000; i++ {
		Set(data)
	}
	fmt.Println(time.Since(starttime))

}

type Tt struct {
	Name     string
	Age      int
	Email    string
	Addr     string
	Nickname string
}

func Set(data Tt) Tt {
	data.Name = "ashan"
	data.Age = 32
	data.Email = "abc@abc.com"
	data.Addr = "china"
	data.Nickname = "ashan"
	return data
}

上面这段代码运行起来需要大约214.323µs。在1ms内完成了,我们稍微修改一下代码再来运行一次。

package main

import (
	"fmt"
	"time"
)

func main() {
	_abc()
}

func _abc() {
	fmt.Println("start")
	starttime := time.Now()
	var data Tt
	for i := 0; i < 10000; i++ {
		Set(&data)
	}
	fmt.Println(time.Since(starttime))

}

type Tt struct {
	Name     string
	Age      int
	Email    string
	Addr     string
	Nickname string
}

func Set(data *Tt) *Tt {
	data.Name = "ashan"
	data.Age = 32
	data.Email = "abc@abc.com"
	data.Addr = "china"
	data.Nickname = "ashan"
	return data
}

func Setint(data *int) *int {
	*data = 5 + 12*8
	return data
}

再次运行,耗时约为50.675µs。时间相差4到5倍之间。

这个例子告诉我们,函数调用传参的时候struct尽量要传递指针。原因很简单,如果不传递指针,在函数内部,会存在自己的作用域,由于域不同,则需要针对传递进来的类型,再次申请内存空间,创建一个值一样的副本,这个操作就相当耗时。

针对这个问题,只能重构修改,目前还没有进行,等待下一个版本优化重构时候在进行调整。

import cycle not allowed 问题

这个问题是在项目最后才出现的,当时非常奇怪,为什么会出现“循环引用”问题,最后发现是由于goalng的import包加载机制导致的。

简单解释一下可以立即为,在包A中 import 包B,而包B中 import 包A。当进行编译时,则发生互相递归引用,从而发生问题。

思考良久,如此问题怎样解决会比较好,产生这个问题的原因可能会出现在一下两种情况中:

  1. 使用的库存在互相应用的问题
  2. 自身模块结构设计存在问题

第一种问题基本属于掉坑了,解决的方法没啥好办法,只能自己想办法调整。

第二种情况可以使用重构来解决,这也是我未来要做的事情。出现这种情况,只能将功能重复的代码作为公用库放到一个独立的包当中,从而避免此类问题发生。

大写与小写

golang算是在语法糖中把“吝啬”做到了机智,在函数对外访问权限设计中,连public 这样的关键词都不提供,直接使用首字母大小写来区分。

一开始我设想所有 private 访问权限函数全部使用 _ 开头。看了一下golang中源码的一些实现方式,并没有这种习惯。索性就不采用这种方式。但很多时候这种规则容易忘记,尤其是我一开始直接使用 Sublime 编写代码时候,由于安装任何插件,没有代码提示,经常大小写搞混。

对于函数调用的问题还好,毕竟编译时候会提示你调用的函数不存在。但将 struct 转为字符串 和借助 mgo 查询数据时,会得到空的结果,极其令人头疼。与此同时,struct 作为数据库查询结果返回的时候,字段名称对应的首字母也要大写,和数据库中字段大小写不一致,这也是个不大不小的问题。

内存

老生常谈的问题又来了,这20天对于golang的接触与使用,并没有太多关注内存的控制,顶多是对变量的开辟小心处理而已,但我相信依然存在不少内存方面的隐患,待仔细研究后再来总结分享。

总结

总体来说,我对golang的使用体验还算满意,用起来像C。开发思路上没遇到大的问题,后续慢慢深入。

enjoy!