研究課題
最近在考慮優(yōu)化程序的執(zhí)行時(shí)間時(shí)勋乾,考慮過(guò)一個(gè)問(wèn)題,就是辑莫,如果有一個(gè)并發(fā)處理的程序学歧,每次調(diào)用時(shí),都需要做一部分預(yù)處理各吨,比如枝笨,發(fā)送http請(qǐng)求時(shí),要先組裝request揭蜒,那么每一次都組裝好了再發(fā)請(qǐng)求和通過(guò)channel預(yù)處理request横浑,發(fā)送是從channel里面獲取會(huì)不會(huì)性能有很大提高呢?
測(cè)試代碼
為此忌锯,我做了一個(gè)小程序檢驗(yàn)伪嫁,代碼如下:
package main
import (
"fmt"
"sync"
"time"
)
func main() {
count, concurrcy := 10, 1
costs := make([]time.Duration, count)
cost1s := make([]time.Duration, count)
for index := 0; index < 10; index++ {
// directly
var wg sync.WaitGroup
wg.Add(concurrcy)
now := time.Now()
for index := 0; index < concurrcy; index++ {
go func() {
directlyGet()
doAnother()
wg.Done()
}()
}
wg.Wait()
costs[index] = time.Since(now)
// channel
var wg1 sync.WaitGroup
wg1.Add(concurrcy)
now1 := time.Now()
for index := 0; index < concurrcy; index++ {
go func() {
<-channelGet()
doAnother()
wg1.Done()
}()
}
wg1.Wait()
cost1s[index] = time.Since(now1)
}
var cost, cost1 float64
for index := 0; index < count; index++ {
cost += costs[index].Seconds()
cost1 += cost1s[index].Seconds()
}
fmt.Println("cost(avg, ms):", cost*1000/float64(count))
fmt.Println("cost1(avg, ms):", cost1*1000/float64(count))
fmt.Println("((cost1-cost)/cost)(%):", ((cost1 - cost) / cost))
}
func directlyGet() string {
doOther()
return "result"
}
func doOther() {
time.Sleep(20 * time.Millisecond)
}
func doAnother() {
time.Sleep(20 * time.Millisecond)
}
func channelGet() <-chan string {
stream := make(chan string)
go func() {
defer close(stream)
doOther()
stream <- "result"
}()
return stream
}
direcltyGet是每次使用時(shí),都要doOther完成偶垮,然后才能doAnother张咳;而channelGet則是將doOther和doAnother并發(fā)處理,簡(jiǎn)單來(lái)說(shuō)就是當(dāng)在doAnother的時(shí)候似舵,另一個(gè)goroutine已經(jīng)在doOther了脚猾。那這個(gè)結(jié)果是怎么樣的呢?這個(gè)程序現(xiàn)在主要影響的參數(shù)有2砚哗,1是concurrcy-并發(fā)量龙助,而是doOther:doAnother,即預(yù)處理部分相對(duì)于后面的處理所占的比例。count是用來(lái)消除單次執(zhí)行的影響提鸟,求取花費(fèi)時(shí)間平均值军援。
實(shí)驗(yàn)結(jié)果
經(jīng)過(guò)幾次調(diào)整后的結(jié)果列入下表(單位:ms):
并發(fā)量count | 消耗比 doOther:doAnother | 平均線性處理 cost | 平均預(yù)處理cost1 | 消耗比1 cost1:cost |
---|---|---|---|---|
1 | 1:0.001 | 20.863898799999998 | 21.0200263 | 0.74831411663098596 |
1 | 1:1 | 41.1631734 | 41.448019099999996 | 0.6919915946033516 |
1 | 1:50 | 1022.5822461 | 1022.6867288000001 | 0.01021753510767501 |
50 | 1:0.001 | 21.314165699999997 | 21.501593299999996 | 0.8793569621165047 |
50 | 1:1 | 42.6392575 | 43.419844499999996 | 1.8306768123248847 |
50 | 1:50 | 1022.7240038 | 1023.0811119 | 0.03491734805022551 |
5000 | 1:0.001 | 23.6074675 | 27.948086 | 18.38663338200085 |
5000 | 1:1 | 47.451019800000005 | 51.9780305 | 9.540386527161635 |
5000 | 1:50 | 1026.7172483 | 1028.0245165000001 | 0.12732504515382329 |
總結(jié)
在doOther固定20ms消耗的情況下(更大消耗無(wú)明顯影響,因?yàn)橄臅r(shí)間是按比例計(jì)算)称勋,經(jīng)過(guò)channel預(yù)處理之后所花費(fèi)時(shí)間無(wú)明顯減少(比例為負(fù)數(shù))胸哥,反而在大并發(fā)量情況下還有所增加,猜測(cè)是由于放大goroutine之間的切換調(diào)度赡鲜,即阻塞與喚醒等空厌。因此,在無(wú)必要情況下银酬,如將輸入轉(zhuǎn)化成流形式嘲更,或者有并發(fā)共享內(nèi)存等的影響,可不必刻意追求將輸入轉(zhuǎn)化為channel流 揩瞪。