線程池
線程池是我們工作中常被用到的叽唱。他是一種線程的使用模式屈呕。線程過多會帶來調(diào)度開銷,進而影響緩存局部性和整體性能棺亭。而線程池維護著多個線程虎眨,等待著監(jiān)督管理者分配可并發(fā)執(zhí)行的任務(wù)。這避免了在處理短時間任務(wù)時創(chuàng)建與銷毀線程的代價。線程池不僅能夠保證內(nèi)核的充分利用嗽桩,還能防止過分調(diào)度(百度百科)岳守。
設(shè)定一個使用場景:API平臺對外提供了一個接口,該接口內(nèi)部需要調(diào)用其它接口或是業(yè)務(wù)層去處理一些事情碌冶,但是客戶端需要快速得到響應(yīng)湿痢,業(yè)務(wù)的處理過程將在后臺被繼續(xù)執(zhí)行。使用Spring的項目中扑庞,一般會用ThreadPoolTaskExecutor來實現(xiàn)一個線程池譬重,調(diào)用時,只需要注入taskExecutor罐氨,開啟線程:
@Autowired
private ThreadPoolTaskExecutor taskExecutor;
public String doJob(){
// 參數(shù)處理
taskExecutor.execute(new Thread() {
public void run() {
// 處理業(yè)務(wù)
}
});
return "SUCCESS";
}
goroutine池
go的概念里應(yīng)該不能叫做線程池了臀规。程序中我們會開啟一個goroutine去執(zhí)行任務(wù):
func startProcessor() {
go dosomething()
}
對于一定量的負載,這種使用方法是沒有問題栅隐,但是當遇到一定大數(shù)量級的請求時塔嬉,程序會不斷的新建goroutine,結(jié)果就是程序崩了租悄。
所以必須要去控制創(chuàng)建的goroutine的數(shù)量邑遏。
第一個簡易的demo
- 創(chuàng)建一個測試的業(yè)務(wù)函數(shù),給一個文件中寫日志
func writeInfo() {
time.Sleep(1 * time.Second)
t := time.Now()
logFile, err := os.OpenFile("syslog.txt", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0766)
defer logFile.Close()
if err != nil {
panic(err)
}
infoLog := log.New(logFile, "[INFO]", log.LstdFlags)
// 隨便往里面寫點東西
infoLog.Print("time=" + strconv.FormatInt(t.UTC().UnixNano(), 10))
}
- 初始化一個帶緩沖的channel恰矩,并使用select去監(jiān)聽通道的操作
var Queue chan int
func init() {
//初始化一個容量為20的'隊列'
Queue = make(chan int, 20)
go startProcessor()
}
func startProcessor() {
// 利用select记盒,當有任務(wù)添加到Queue中時,執(zhí)行業(yè)務(wù)操作
for {
select {
case <-Queue:
fmt.Println("開始執(zhí)行任務(wù)--------------")
writeInfo()
}
}
}
- 提供一個監(jiān)聽端口和路由外傅,用于測試
func indexHandler(w http.ResponseWriter, r *http.Request) {
Queue <- 1
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
result := "{\"msg\":\"SUCCESS\",\"code\":0}"
fmt.Fprintln(w, result)
}
func main() {
http.HandleFunc("/test/pool/", indexHandler)
http.ListenAndServe(":9000", nil)
}
筆記
假設(shè)隊列容量在服務(wù)器性能范圍內(nèi)已經(jīng)足夠大纪吮,那么這種方式是具有一定作用的,他可以有效避免因為無限制創(chuàng)建goroutine而引起的程序崩潰萎胰。但是當請求接口的速率遠比處理業(yè)務(wù)(writeInfo)的速率要大碾盟,而且請求的量級也很大,那我們所創(chuàng)建的channel就會達到他的極限技竟,會有一部分請求被阻塞冰肴,客戶端請求響應(yīng)的時間也會增加。
比如demo中的channel的容量為20榔组,使用jmeter并發(fā)100個請求熙尉,循環(huán)10次:
可以看到偏移量已經(jīng)很大了,并且平均響應(yīng)時間也很長搓扯,要是再加大并發(fā)的樣本數(shù)量检痰,我的電腦就扛不住了。