物件池模式,物件被預先建立並初始化後放入物件池中,物件提供者,物件提供者就能利用已有的物件來處理請求,減少物件頻繁建立所浪費的資源。例如資料庫的連線池等等,基本都是建立後就被放入連線池中,後續的查詢請求使用的都是連線池中的物件,從而加快了查詢速度(不然每次查詢都需要重新建立資料庫連線物件,比較浪費)。
一句話解釋,物件池模式下,程式在一開始就建立好了一批可用物件供使用這種模式下,一般有兩種角色,即物件池管理者和物件池使用者。
物件池管理者負責管理整個物件池,包括初始化物件池,擴充物件池的大小,重置歸還物件的狀態等等。
物件池使用者負責從物件池中獲取乙個物件,用完之後一般需要歸還整這個物件。
一般被放入物件池中的物件包括socket物件,資料庫連線物件(連線池),執行緒物件(執行緒池)等等。
來看看物件池模式的五大要素:
go語言內部有sync.pool
包實現了物件池的概念,但是這個設計出來的目的是優化gc的,因為它儲存的物件隨時都有可能被gc**掉,具體感興趣地可以去了解一下該包的用法,這篇文章就不對該包作詳細解答了,因為我們的主要目的還是了解物件池模式。因此下面我們會自己實現乙個物件池。
當前的場景是我們需要實現乙個協程池,我們開始給這個協程池固定乙個協程數量,每個協程被用於去執行一項任務(task),假設當前有1萬個任務,我們必不可能用只用乙個協程去執行,我們開啟若干個協程去不斷地輪詢執行這些任務
object_pool.go
:
package objectpool
import
("fmt"
"sync"
)// 任務物件,任務具體做什麼由f決定
type task struct
// 建立乙個任務物件
func
newtask
(f func()
error
,id int
)*task
}// 執行該任務物件
func
(t *task)
execute()
error
// 協程池物件
type pool struct
// 建立乙個協程池
func
newpool
(cap
int, wg *sync.waitgroup)
*pool
}func
(p *pool)
settask
(task *task)
func
(p *pool)
worker
(workid int
)else
// 完成乙個任務done
p.wg.
done()
}}func
(p *pool)
run(
)for task :=
range p.entrychannel
}func
(p *pool)
stop()
object_pool_test.go
:
package objectpool
import
("fmt"
"sync"
"testing"
"time"
)func
testobjectpool
(t *testing.t)()
wg :=
&sync.waitgroup
p :=
newpool(10
,wg)
go p.
run(
)// 建立100個task
for i :=
0; i <
100; i++
,i) p.
settask
(t)}
wg.wait()
p.stop()
}
執行測試結果:
==
= run testobjectpool
workerid: 8, the task id 8 was successfully executed
workerid: 2, the task id 4 was successfully executed
....
....
....
.....
....
....
.....
workerid: 6, the task id 2 was successfully executed
workerid: 6, the task id 97 was successfully executed
workerid: 2, the task id 99 was successfully executed
it takes 10.030659 seconds
--- pass: testobjectpool (10.03s)
pass
上述例子在做測試的時候,我特意在每個task任務中 sleep了1秒,保證它們至少執行1秒再推出。如果每個任務中只是列印乙個日誌,這樣我們在測試的時候會發現,可能協程池開的worker數越少越好,因為這個時候在一開始建立多個worker的開銷已經遠遠超過每個任務執行的開銷了。因此協程數不是開的越多越好,具體開多少個是需要在指定場景進行效能測試才能決定的。
Go實現設計模式系列(2) Go實現New模式
這幾乎是我們最常用的模式,因為太常用了,以致於我們並沒有它當成一種模式。new 模式屬於建立型模式的一種,作為最基礎的建立型模式而被我們廣泛使用 來看看new模式的五大要素 我們想要獲取乙個伺服器物件,該伺服器物件實現了start,stop兩個介面 new.go package newimport ...
8 Go語言 指標型別
1.實際用法package main import fmt func main 執行結果 0xc042052088 0xc0420461b02.從指標獲取指標指向的值 在對普通變數使用 操作符取位址獲得這個變數的指標後,可以對指標使用 操作,也就是指標取值 package main import f...
GO學習 8 Go語言基礎之陣列
陣列是同一種資料型別元素的集合。在go語言中,陣列從宣告時就確定,使用時可以修改陣列成員,但是陣列大小不可變化。基本語法 定義乙個長度為3元素型別為int的陣列a var a 3 intvar 陣列變數名 元素數量 t比如 var a 5 int,陣列的長度必須是常量,並且長度是陣列型別的一部分。一...