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();
}
