日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

Golang?WorkerPool線程池并發模式示例詳解_Golang

作者:龔國瑋 ? 更新時間: 2022-10-12 編程語言

?正文

Worker Pools 線程池是一種并發模式。該模式中維護了固定數量的多個工作器,這些工作器等待著管理者分配可并發執行的任務。該模式避免了短時間任務創建和銷毀線程的代價。

golang 中,我們使用 goroutinechannel 來構建這種模式。工作器 worker 由一個 goroutine 定義,該 goroutine 通過 channel 獲取數據。

處理CVS文件記錄

接下來讓我們通過一個例子,來進一步理解該模式。假設您需要處理來自 CVS 文件的記錄數據,我們需要將該文件中的經緯度保存到數據庫中。代碼如下。

package main
import (
	"encoding/csv"
	"fmt"
	"os"
	"time"
)
type city struct {
	name     string
	location string
}
func createCity(record city) {
	time.Sleep(10 * time.Millisecond)
}
func main() {
	startTime := time.Now()
	csvFile, err := os.Open("cities.csv")
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println("Successfully Opened CSV file")
	defer csvFile.Close()
	csvLines, err := csv.NewReader(csvFile).ReadAll()
	if err != nil {
		fmt.Println(err)
	}
	counter := 0
	for _, line := range csvLines {
		counter++
		createCity(city{
			name:     line[0],
			location: line[1],
		})
	}
	fmt.Println("records saved:", counter)
	fmt.Println("total time:", time.Since(startTime))
}

?? 獲取測試數據

cities.csv

輸出:

正如我們所看到的,保存 CSV 中所有記錄需要 55 秒,這是很長的時間,可能會導致很多性能問題。用戶如果想要上傳 CSV 文件,那體驗感一定很差。

如何解決這個問題?那我們就使用線程池的方法試試看。

線程池耗時差異

在如下示例中,我們將解決相同的需求,但通過線程池,耗時方面,我們能夠看到巨大的差異。來吧!

代碼如下

package main
import (
	"encoding/csv"
	"fmt"
	"os"
	"time"
)
type city struct {
	name     string
	location string
}
func createCity(record city) {
	time.Sleep(10 * time.Millisecond)
}
func readData(cityChn chan []city) {
	var cities []city
	csvFile, err := os.Open("cities.csv")
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println("Successfully Opened CSV file")
	defer csvFile.Close()
	csvLines, err := csv.NewReader(csvFile).ReadAll()
	if err != nil {
		fmt.Println(err)
	}
	for _, line := range csvLines {
		cities = append(cities, city{
			name:     line[0],
			location: line[1],
		})
	}
	cityChn <- cities
}
func worker(cityChn chan city) {
	for val := range cityChn {
		createCity(val)
	}
}
func main() {
	startTime := time.Now()
	cities := make(chan []city)
	go readData(cities)
	const workers = 5
	jobs := make(chan city, 1000)
	for w := 1; w <= workers; w++ {
		go worker(jobs)
	}
	counter := 0
	for _, val := range <-cities {
		counter++
		jobs <- val
	}
	fmt.Println("records saved:", counter)
	fmt.Println("total time:", time.Since(startTime))
}

輸出:

你看到很大的不同了嗎?現在同樣的過程只需要 8 秒。正如您所見,當我們需要處理大量數據時,線程池非常有用。

使用線程池,我們必須定義一個函數,在示例中該函數為 worker,該函數用于定義工作進程,您可以看到它接收一個 Channel 通道來處理數據。 另外,我們必須在數據傳遞到通道之前啟動 goroutines 協程,當 Channel 通道獲取到值時,goroutines 工作者開始處理它們。

?? 現在您知道如何實現線程池了!

原文鏈接:https://juejin.cn/post/7132421198964588575

欄目分類
最近更新