This is a creation in Article, where the information may have evolved or changed.
This article wants to talk about how to give gc
the burden of the problem, that is, when we write business, sometimes need to consider the feelings of the gc
elderly, but can not lose the readability of the code, in some cases, the code needs no optimization, optimization can achieve how much performance improvement, in which the balance needs to be grasped. Otherwise it is easy to appear: Take off the trousers fart, superfluous.
- string concatenation, Demo code:
package mainimport ( "bytes")func f1(l int) { var s, s1 string = ``, `hello world` for i := 0; i < l; i++ { s = s + s1 }}func f2(l int) { buf := bytes.NewBuffer([]byte{}) var s1 string = `hello world` for i := 0; i < l; i++ { buf.WriteString(s1) }}func f3(l int) { var s []string var s1 string = `hello world` for i := 0; i < l; i++ { s = append(s, s1) } strings.Join(s, ``)}
Test code:
package mainimport ( "testing")func Benchmark_F1(b *testing.B) { for i := 0; i < b.N; i++ { f1(100000) }}func Benchmark_F2(b *testing.B) { for i := 0; i < b.N; i++ { f2(100000) }}func Benchmark_F3(b *testing.B) { for i := 0; i < b.N; i++ { f3(100000) }}
go test -bench=".*" -test.benchmem -count=1
The result of the output is:
Benchmark_F1-4 1 9334113815 ns/op 55401130720 B/op 100056 allocs/opBenchmark_F2-4 1000 2318146 ns/op 2891600 B/op 18 allocs/opBenchmark_F3-4 100 14660804 ns/op 11459184 B/op 32 allocs/opPASSok _/Users/taomin/pprof/string 13.394s
Judging from the results of bench, 10W concatenation of strings, +
the worst, the bytes.NewBuffe
best. The gap between memory and time is about 3 orders of magnitude. This optimization of string stitching, unless your scene does have a large number of string stitching, otherwise do not use bytes
or strings.join
, directly +
splicing up the good.
temporary object pool
Object pool stores objects in a pool, reducing the number of allocated objects by reusing previous objects. Each time Gc,runtime calls the Poolcleanup function to empty the pool so that the objects stored in the pool are all recycled by the GC. This is a feature of the pool, which causes a state object not to be stored in the pool, which is not used as a connection pool; The official documentation is described as follows:
A Pool is a set of temporary objects, may individually saved and retrieved. Any item stored in the Pool is removed automatically at any time without notification. If The Pool holds the only reference when this happens, the item might is deallocated. A Pool is safe for use by multiple goroutines simultaneously. Pool ' s purpose is to cache allocated but unused items for later reuse, relieving pressure on the garbage collector. That's, it makes it easy-to-build efficient, thread-safe free lists. However, it isn't suitable for all free lists. An appropriate use of a Pool was to manage a group of temporary items silently gkfx among and potentially reused by Concu Rrent independent clients of a package. Pool provides a to amortize allocation overhead across many clients. An example of good use of a Pool are in the FMT package, which maintains a dynamically-sized store of temporary output buff ERs. The store scales under load (when many goroutines is actively printing) and shrinks WHen quiescent. On the other hand, a free list maintained as part of a short-lived object was not a suitable with a Pool, since the over Head does not amortize well in that scenario. It is more efficient to has such objects implement their own free list. A Pool must not being copied after first Use.type Pool struct {//New optionally specifies a function to generate A value when Get would otherwise return nil. It May is changed concurrently with calls to Get. New func () interface{}//contains filtered or unexported fields}
There is an example of the pool that the buddy wrote on the internet, and I think it is a good illustration of the problem, here is an example of his code:
Package Mainimport ("FMT" "io" "net/http" "sync")//How many times the concurrent process used []bytevar mu sync. Mutexvar Holder Map[string]bool = make (Map[string]bool)//Temporary object pool var p = sync. pool{new:func () interface{} {buffer: = make ([]byte, 1024x768) return &buffer},}func readcontent (WG *sync. Waitgroup) {defer WG. Done () resp, err: = http. Get ("Http://my.oschina.net/xinxingegeya/home") if err! = Nil {fmt. PRINTLN (ERR)} Defer resp. Body.close () Byteslice: = P.get (). (*[]byte)//Type assertion key: = FMT. Sprintf ("%p", Byteslice) mu. Lock () _, OK: = Holder[key] If!ok {Holder[key] = true} mu. Unlock () _, err = Io. Readfull (resp. Body, *byteslice) if err! = Nil {fmt. PRINTLN (Err)} p.put (Byteslice)}func main () {var wg sync. Waitgroup for I: = 0; I < 10; i++ {WG. ADD (1) Go ReadContent (&WG)} WG. Wait () for key, Val: = range Holder {fmt. Println ("Key:", Key, "Value:", Val)}}
The pool should be used with caution, because its temper is not very good.
- String to byte array
The value inside a variable of type string is copied into the byte array, before rain Rainbow Academy an optimization idea, through unsafe
the pointer operation of the package, directly to the address of the string to operate, thus avoiding the memory copy operation, but personally feel this optimization is a bit too, this will make the code lost readability, For example:
s := "hello world!"b := []byte(s)
was changed to:
func str2bytes(s string) []byte { x := (*[2]uintptr)(unsafe.Pointer(&s)) h := [3]uintptr{x[0], x[1], x[1]} return *(*[]byte)(unsafe.Pointer(&h))}
The following code if not a good study, completely do not understand the god horse. These are the optimization points that you can think of, what are your best optimization programs and experiences, welcome to share ...
End ~