package main; import ( "sync" "fmt" "net" "runtime" ) //sync.Pool是一個可以存或取的臨時對象集合 //sync.Pool可以安全被多個線程同時使用,保證線程安全 //注意、注意、注意,sync.Pool中保存的任何項都可能隨時不做通知的釋放掉,所以不適合用於像socket長連接或數據庫連接池。 //sync.Pool主要用途是增加臨時對象的重用率,減少GC負擔。 func testTcpConnPool() { sp2 := sync.Pool{ New: func() interface{} { conn, err := net.Dial("tcp", ":80"); if err != nil { return nil; } return conn; }, }; buf := make([]byte, 1024); //獲取對象 conn := sp2.Get().(net.Conn); //使用對象 conn.Write([]byte("GET / HTTP/1.1 \r\n\r\n")); n, _ := conn.Read(buf); fmt.Println("conn read : ", string(buf[:n])); //打印conn的地址 fmt.Println(conn); //把對象放回池中 sp2.Put(conn); //我們人為的進行一次垃圾回收 runtime.GC(); //再次獲取池中的對象 conn2 := sp2.Get().(net.Conn); //這時發現conn2的地址與上面的conn的地址不一樣了 //說明池中我們之前放回的對象被全部清除了,顯然這並不是我們想看到的 //所以sync.Pool不適合用於scoket長連接或數據庫連接池 fmt.Println(conn2); } func main() { //我們創建一個Pool,並實現New()函數 sp := sync.Pool{ //New()函數的作用是當我們從Pool中Get()對象時,如果Pool為空,則先通過New創建一個對象,插入Pool中,然后返回對象。 New: func() interface{} { return make([]int, 16); }, }; item := sp.Get(); //打印可以看到,我們通過New返回的大小為16的[]int fmt.Println("item : ", item); //然后我們對item進行操作 //New()返回的是interface{},我們需要通過類型斷言來轉換 for i := 0; i < len(item.([]int)); i++ { item.([]int)[i] = i; } fmt.Println("item : ", item); //使用完后,我們把item放回池中,讓對象可以重用 sp.Put(item); //再次從池中獲取對象 item2 := sp.Get(); //注意這里獲取的對象就是上面我們放回池中的對象 fmt.Println("item2 : ", item2); //我們再次獲取對象 item3 := sp.Get(); //因為池中的對象已經沒有了,所以又重新通過New()創建一個新對象,放入池中,然后返回 //所以item3是大小為16的空[]int fmt.Println("item3 : ", item3); //測試sync.Pool保存socket長連接池 testTcpConnPool(); }