Go語言的 序列處理 和 並行處理 有什麼區別 ?
阿新 • • 發佈:2022-12-05
收錄於合集#為什麼要學Go語言141個 學習與交流:Go語言技術微信群
商務合作加微信:LetsFeng
goland 全家桶啟用碼,支援所有版本,支援所有系統
連結:http://web.52shizhan.cn/activity/s2abxc
提取碼:GJF9B1DK
現在就開始你的Go語言學習之旅吧!人生苦短,let’s Go.
程式運算時往往需要資料,而資料的IO又往往需要時間傳輸,而常見的序列處理,是一個任務處理完成才接著處理新的任務, 其效率低下可想而知。
假如有3個任務要處理,而每個任務都有一定的阻塞,序列處理大概是這個樣子:
main.go
package main
import (
"fmt"
"time"
)
type Task struct {
Duration time.Duration
Name string
}
func main() {
// 宣告要處理的任務
taskList := []Task {
{
1,
"處理1",
},
{
2,
"處理2",
},
{
3,
"處理3",
},
}
starTime := time.Now().Unix()
for _, item := range taskList {
goProcess(item)
}
fmt.Printf("用時:%ds\n", time.Now().Unix() - starTime)
}
/**
* 進行處理
*/
func goProcess(task Task) {
time.Sleep(time.Second * task.Duration) // 假設這是io阻塞會在這裡阻塞一些時間,而這些io可能是網路io也可能是磁碟io等,io完成後才會接著執行下去
fmt.Printf("任務:%s 處理完畢\n", task.Name)
}
處理列印結果
任務:處理1 處理完畢
任務:處理2 處理完畢
任務:處理3 處理完畢
用時:6s
這種序列處理遇到IO阻塞時,弊端就是太費時間了
可以看到,程式在計算時或許用不到多少時間反而是IO阻塞佔用了大量的時間。這種佔著茅坑不拉屎,外面等著人直跳腳,確實不太好。而用非同步處理則可以跳過阻塞,達到避免佔坑的情況發生。
用協程的話,則可以在阻塞時先非同步執行下去而不用等待,等所有協程都處理結束,再把處理的結果彙總起來就可以了,程式碼大概是這樣子:
main.go
package main
import (
"fmt"
"sync"
"time"
)
type Task struct {
Duration time.Duration
Name string
}
func main() {
// 宣告要處理的任務
taskList := []Task {
{
1,
"處理1",
},
{
2,
"處理2",
},
{
3,
"處理3",
},
}
starTime := time.Now().Unix()
var res []string //處理結果收集
resChang := make(chan string, len(taskList))
wg := &sync.WaitGroup{}
// 這裡收集非同步處理的結果, 通過管道把資料傳遞過來,類似於單一訂閱功能吧
go func() {
wg.Add(1)
defer wg.Done() // 通道關閉後 處理結果也收集完畢,則觸發 用於通知下方批處理,處理結果已經收集完畢
for resItem := range resChang {
res = append(res, resItem)
}
}()
taskWG := &sync.WaitGroup{}
for _, item := range taskList {
taskWG.Add(1) // 批處理 訊號量+1
go goProcess(item, &resChang, taskWG)
}
taskWG.Wait()// 這裡阻塞,等待所有處理執行完畢, 才接著執行下去
close(resChang)// 已經處理完畢後就關閉處理傳輸通道
wg.Wait() // 這是阻塞 等待處理收集完畢, 才接著執行去
// 列印批處理收集的處理結果
for _, i := range res {
fmt.Printf("%s", i)
}
fmt.Printf("用時:%ds\n", time.Now().Unix() - starTime)
}
/**
* 進行處理
*/
func goProcess(task Task, resChan *chan string, taskWG *sync.WaitGroup) {
time.Sleep(time.Second * task.Duration) // 假設這是io阻塞會在這裡阻塞一些時間,而這些io可能是網路io也可能是磁碟io等,才會接著執行下去
res := fmt.Sprintf("任務:%s 處理完畢\n", task.Name)
defer func() {
*resChan <- res // 把處理結果傳出去
taskWG.Done() // 批處理訊號量-1 來報告處理完畢
}()
}
執行結果
任務:處理1 處理完畢
任務:處理2 處理完畢
任務:處理3 處理完畢
用時:3s
相對於之前的序列,這次的並行有效處理IO的阻塞,相當於,序列就是佔坑不用的角,並行則不管這些,你不用,先把你踹開,給有需要的人用先,這樣一腳腳的踹,效率就上一來了。
文章首發:https://www.jb51.net/article/216996.htm
更多相關Go語言的技術文章或視訊教程,請關注本公眾號獲取並檢視,感謝你的支援與信任!