go fmt.Sprintf的性能分析

背景

最近在開發的項目,大量用到了fmt.Sprintf去做int/uint32/float 轉string, 結果壓測的時候竟然發現fmt.Sprintf耗時較大,有性能問題。

分析

通過查看fmt.Sprintf源碼, 可以看出效率低有兩個原因:

  1. fmt.Sprintf 接受的類型是 interface{},內部使用了反射。所以,與相應的標準庫函數相比,fmt.Sprintf 需要更大的開銷
  2. fmt.Sprintf 的用途是格式化字符串,需要去解析格式串,比如%s%d之類的
func Sprintf(format string, a ...interface{}) string {
	p := newPrinter()
	p.doPrintf(format, a)
	s := string(p.buf)
	p.free()
	return s
}


func (p *pp) doPrintf(format string, a []interface{}) {
	end := len(format)
	argNum := 0         // we process one argument per non-trivial format
	afterIndex := false // previous item in format was an index like [3].
	p.reordered = false
formatLoop:
	for i := 0; i < end; {
		p.goodArgNum = true
		lasti := i
		for i < end && format[i] != '%' {
			i++
		}
		if i > lasti {
			p.buf.writeString(format[lasti:i])
		}
		if i >= end {
			// done processing format string
			break
		}

		// Process one verb
		i++

		// Do we have flags?
		p.fmt.clearflags()
	simpleFormat:
		for ; i < end; i++ {
			c := format[i]
			switch c {
			case '#':
				p.fmt.sharp = true
			case '0':
				p.fmt.zero = !p.fmt.minus // Only allow zero padding to the left.
			case '+':
				p.fmt.plus = true
			case '-':
				p.fmt.minus = true
				p.fmt.zero = false // Do not pad with zeros to the right.
			case ' ':
				p.fmt.space = true
			default:
				// Fast path for common case of ascii lower case simple verbs
				// without precision or width or argument indices.
				if 'a' <= c && c <= 'z' && argNum < len(a) {
					if c == 'v' {
						// Go syntax
						p.fmt.sharpV = p.fmt.sharp
						p.fmt.sharp = false
						// Struct-field syntax
						p.fmt.plusV = p.fmt.plus
						p.fmt.plus = false
					}
					p.printArg(a[argNum], rune(c))
					argNum++
					i++
					continue formatLoop
				}
				// Format is more complex than simple flags and a verb or is malformed.
				break simpleFormat
			}
		}

結論

  1. 不要使用fmt.Sprintf去做類型轉換,更好的做法是使用標準庫函數strconv, 推薦使用 strconv.FormatIntint64),對於 int 類型,strconv.Itoa 對前者做了一個封裝。

參考

http://liyangliang.me/posts/2014/06/donnot-use-fmt-sprintf-for-type-conversion/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章