當 goroutine 數量增加時,Go 程式會變慢。這是因為 goroutine 的調度和切換會引入額外的開銷,從而導致程式效能下降。雖然 goroutine 在提供並發效能方面表現出色,但是過多的 goroutine 會導致執行緒競爭和資源爭用,進而影響程式的執行效率。為了避免這種情況發生,我們需要合理管理和控制 goroutine 的數量,確保程式能夠有效率地運作。在本文中,php小編柚子將為您介紹一些優化 goroutine 效能的方法和技巧,幫助您提升 Go 程式的執行效率。
我正在為我的平行課程做一個小項目,我已經嘗試使用緩衝通道、無緩衝通道、不使用指向切片的指標的通道等。此外,盡可能嘗試優化它(不是當前狀態)但我仍然得到相同的結果:增加 goroutine 數量(甚至增加 1)會減慢整個程式的速度。有人可以告訴我我做錯了什麼嗎?在這種情況下甚至可以增強並行性嗎?
這是部分程式碼:
func main() { rand.seed(time.now().unixmicro()) numagents := 2 fmt.println("please pick a number of goroutines: ") fmt.scanf("%d", &numagents) numfiles := 4 fmt.println("how many files do you want?") fmt.scanf("%d", &numfiles) start := time.now() numassist := numfiles channel := make(chan []file, numagents) files := make([]file, 0) for i := 0; i < numagents; i++ { if i == numagents-1 { go generatefiles(numassist, channel) } else { go generatefiles(numfiles/numagents, channel) numassist -= numfiles / numagents } } for i := 0; i < numagents; i++ { files = append(files, <-channel...) } elapsed := time.since(start) fmt.printf("function took %s\n", elapsed) }
func generatefiles(numfiles int, channel chan []file) { magicnumbersmap := getmap() files := make([]file, 0) for i := 0; i < numfiles; i++ { content := randelementfrommap(&magicnumbersmap) length := rand.intn(400) + 100 hexslice := gethex() for j := 0; j < length; j++ { content = content + hexslice[rand.intn(len(hexslice))] } hash := getsha1hash([]byte(content)) file := file{ content: content, hash: hash, } files = append(files, file) } channel <- files }
預期透過增加 goroutines,程式會運行得更快,但達到一定數量的 goroutines,此時透過增加 goroutines,我將獲得相同的執行時間或稍慢一些。
編輯:使用的所有功能:
import ( "crypto/sha1" "encoding/base64" "fmt" "math/rand" "time" ) type File struct { content string hash string } func getMap() map[string]string { return map[string]string{ "D4C3B2A1": "Libcap file format", "EDABEEDB": "RedHat Package Manager (RPM) package", "4C5A4950": "lzip compressed file", } } func getHex() []string { return []string{ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", } } func randElementFromMap(m *map[string]string) string { x := rand.Intn(len(*m)) for k := range *m { if x == 0 { return k } x-- } return "Error" } func getSHA1Hash(content []byte) string { h := sha1.New() h.Write(content) return base64.URLEncoding.EncodeToString(h.Sum(nil)) }
簡單來說 - 檔案產生程式碼不夠複雜,不足以證明並行執行的合理性。所有上下文切換和透過通道移動資料都會消耗並行處理的所有好處。
如果你在generatefiles
函數的循環中加入類似time.sleep(time.millisecond * 10)
的內容,就好像它在做更複雜的事情一樣,你會看到你期望看到的東西- 更多的goroutine 工作得更快。但同樣,只有到一定程度,並行處理的額外工作才會帶來好處。
另請注意,程式最後一位的執行時間:
for i := 0; i < numAgents; i++ { files = append(files, <-channel...) }
直接取決於 goroutine 的數量。由於所有 goroutine 大約同時完成,因此該循環幾乎不會與您的工作線程並行執行,並且運行所需的時間只是添加到總時間中。
接下來,當您多次追加到 files
切片時,它必須成長幾次並將資料複製到新位置。您可以透過最初建立一個切片來填充所有結果元素(幸運的是,您確切知道需要多少元素)來避免這種情況。
以上是當 goroutine 數量增加時,Go 程式會變慢的詳細內容。更多資訊請關注PHP中文網其他相關文章!