Go語言的并發(fā)模型是其核心特性之一,它通過goroutines和channels提供了一種相對簡單而強大的方式來處理并發(fā)任務(wù)。下面我將通過幾個案例分析來展示Go語言并發(fā)模型的應(yīng)用。
假設(shè)我們要構(gòu)建一個并發(fā)HTTP服務(wù)器,該服務(wù)器能夠同時處理多個客戶端請求。我們可以使用goroutines來實現(xiàn)這一點。
package main
import (
"fmt"
"net/http"
)
func handler(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, World!")
}
func main() {
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)
}
在上面的代碼中,我們定義了一個簡單的HTTP處理函數(shù)handler
,它只是向客戶端發(fā)送一條"Hello, World!"消息。在main
函數(shù)中,我們使用http.HandleFunc
將處理函數(shù)與路徑"/"
關(guān)聯(lián)起來,并使用http.ListenAndServe
啟動服務(wù)器監(jiān)聽8080端口。由于HTTP請求是并發(fā)的,服務(wù)器會為每個請求創(chuàng)建一個新的goroutine來處理,從而實現(xiàn)并發(fā)處理。
假設(shè)我們要構(gòu)建一個并發(fā)任務(wù)調(diào)度系統(tǒng),該系統(tǒng)能夠同時執(zhí)行多個任務(wù)。我們可以使用goroutines和channels來實現(xiàn)這一點。
package main
import (
"fmt"
"sync"
)
func worker(id int, jobs <-chan int, results chan<- int) {
for j := range jobs {
fmt.Printf("Worker %d started job %d\n", id, j)
// 模擬任務(wù)執(zhí)行時間
fmt.Printf("Worker %d finished job %d\n", id, j)
results <- j * 2
}
}
func main() {
const numJobs = 5
jobs := make(chan int, numJobs)
results := make(chan int, numJobs)
var wg sync.WaitGroup
for w := 1; w <= 3; w++ {
wg.Add(1)
go worker(w, jobs, results)
}
// 發(fā)送任務(wù)到j(luò)obs通道
for j := 1; j <= numJobs; j++ {
jobs <- j
}
close(jobs)
// 等待所有工作完成
wg.Wait()
// 打印結(jié)果
for a := 1; a <= numJobs; a++ {
fmt.Println("Result:", <-results)
}
}
在上面的代碼中,我們定義了一個worker
函數(shù),它從jobs
通道接收任務(wù)并執(zhí)行,然后將結(jié)果發(fā)送到results
通道。在main
函數(shù)中,我們創(chuàng)建了三個工作goroutine,并使用sync.WaitGroup
來等待它們完成。然后,我們向jobs
通道發(fā)送任務(wù),并在所有任務(wù)完成后關(guān)閉通道。最后,我們從results
通道接收并打印結(jié)果。
假設(shè)我們要構(gòu)建一個并發(fā)文件讀寫系統(tǒng),該系統(tǒng)能夠同時讀取和寫入多個文件。我們可以使用goroutines和channels來實現(xiàn)這一點。
package main
import (
"fmt"
"io/ioutil"
"os"
"sync"
)
func readFile(filename string, wg *sync.WaitGroup, results chan<- string) {
defer wg.Done()
data, err := ioutil.ReadFile(filename)
if err != nil {
results <- fmt.Sprintf("Error reading %s: %v", filename, err)
return
}
results <- string(data)
}
func writeFile(filename string, data string, wg *sync.WaitGroup) {
defer wg.Done()
err := ioutil.WriteFile(filename, []byte(data), 0644)
if err != nil {
fmt.Printf("Error writing %s: %v\n", filename, err)
return
}
}
func main() {
filenames := []string{"file1.txt", "file2.txt", "file3.txt"}
data := "Hello, World!"
var wg sync.WaitGroup
results := make(chan string, len(filenames))
// 啟動讀取goroutines
for _, filename := range filenames {
wg.Add(1)
go readFile(filename, &wg, results)
}
// 等待讀取完成
go func() {
wg.Wait()
close(results)
}()
// 處理讀取結(jié)果
for result := range results {
fmt.Println(result)
}
// 啟動寫入goroutines
for _, filename := range filenames {
wg.Add(1)
go writeFile(filename, data, &wg)
}
// 等待寫入完成
wg.Wait()
fmt.Println("All files have been processed.")
}
在上面的代碼中,我們定義了readFile
和writeFile
函數(shù),分別用于讀取和寫入文件。在main
函數(shù)中,我們創(chuàng)建了讀取和寫入goroutines,并使用sync.WaitGroup
來等待它們完成。我們還使用了一個results
通道來收集讀取結(jié)果。最后,我們打印處理結(jié)果并等待所有寫入操作完成。
這些案例展示了Go語言并發(fā)模型的強大功能和靈活性。通過使用goroutines和channels,我們可以輕松地構(gòu)建并發(fā)應(yīng)用程序,并有效地處理并發(fā)任務(wù)。