golang的串行處理和并行處理區(qū)別
程序運(yùn)算時(shí)往往需要數(shù)據(jù),而數(shù)據(jù)的IO又往往需要時(shí)間傳輸,而常見(jiàn)的串行處理,是一個(gè)任務(wù)處理完成才接著處理新的任務(wù), 其效率低下可想而知。 假如有3個(gè)任務(wù)要處理,而每個(gè)任務(wù)都有一定的阻塞,串行處理大概是這個(gè)樣子:
main.go
package main
import (
"fmt"
"time"
)
type Task struct {
Duration time.Duration
Name string
}
func main() {
// 聲明要處理的任務(wù)
taskList := []Task {
{
1,
"處理1",
},
{
2,
"處理2",
},
{
3,
"處理3",
},
}
starTime := time.Now().Unix()
for _, item := range taskList {
goProcess(item)
}
fmt.Printf("用時(shí):%ds\n", time.Now().Unix() - starTime)
}
/**
* 進(jìn)行處理
*/
func goProcess(task Task) {
time.Sleep(time.Second * task.Duration) // 假設(shè)這是io阻塞會(huì)在這里阻塞一些時(shí)間,而這些io可能是網(wǎng)絡(luò)io也可能是磁盤(pán)io等,io完成后才會(huì)接著運(yùn)行下去
fmt.Printf("任務(wù):%s 處理完畢\n", task.Name)
}
處理打印結(jié)果
任務(wù):處理1 處理完畢
任務(wù):處理2 處理完畢
任務(wù):處理3 處理完畢
用時(shí):6s
這種串行處理遇到IO阻塞時(shí),弊端就是太費(fèi)時(shí)間了
可以看到,程序在計(jì)算時(shí)或許用不到多少時(shí)間反而是IO阻塞占用了大量的時(shí)間。這種占著茅坑不拉屎,外面等著人直跳腳,確實(shí)不太好。而用異步處理則可以跳過(guò)阻塞,達(dá)到避免占坑的情況發(fā)生。
用協(xié)程的話,則可以在阻塞時(shí)先異步執(zhí)行下去而不用等待,等所有協(xié)程都處理結(jié)束,再把處理的結(jié)果匯總起來(lái)就可以了,代碼大概是這樣子:
main.go
package main
import (
"fmt"
"sync"
"time"
)
type Task struct {
Duration time.Duration
Name string
}
func main() {
// 聲明要處理的任務(wù)
taskList := []Task {
{
1,
"處理1",
},
{
2,
"處理2",
},
{
3,
"處理3",
},
}
starTime := time.Now().Unix()
var res []string //處理結(jié)果收集
resChang := make(chan string, len(taskList))
wg := &sync.WaitGroup{}
// 這里收集異步處理的結(jié)果, 通過(guò)管道把數(shù)據(jù)傳遞過(guò)來(lái),類似于單一訂閱功能吧
go func() {
wg.Add(1)
defer wg.Done() // 通道關(guān)閉后 處理結(jié)果也收集完畢,則觸發(fā) 用于通知下方批處理,處理結(jié)果已經(jīng)收集完畢
for resItem := range resChang {
res = append(res, resItem)
}
}()
taskWG := &sync.WaitGroup{}
for _, item := range taskList {
taskWG.Add(1) // 批處理 信號(hào)量+1
go goProcess(item, &resChang, taskWG)
}
taskWG.Wait()// 這里阻塞,等待所有處理執(zhí)行完畢, 才接著運(yùn)行下去
close(resChang)// 已經(jīng)處理完畢后就關(guān)閉處理傳輸通道
wg.Wait() // 這是阻塞 等待處理收集完畢, 才接著運(yùn)行去
// 打印批處理收集的處理結(jié)果
for _, i := range res {
fmt.Printf("%s", i)
}
fmt.Printf("用時(shí):%ds\n", time.Now().Unix() - starTime)
}
/**
* 進(jìn)行處理
*/
func goProcess(task Task, resChan *chan string, taskWG *sync.WaitGroup) {
time.Sleep(time.Second * task.Duration) // 假設(shè)這是io阻塞會(huì)在這里阻塞一些時(shí)間,而這些io可能是網(wǎng)絡(luò)io也可能是磁盤(pán)io等,才會(huì)接著運(yùn)行下去
res := fmt.Sprintf("任務(wù):%s 處理完畢\n", task.Name)
defer func() {
*resChan <- res // 把處理結(jié)果傳出去
taskWG.Done() // 批處理信號(hào)量-1 來(lái)報(bào)告處理完畢
}()
}
運(yùn)行結(jié)果
任務(wù):處理1 處理完畢
任務(wù):處理2 處理完畢
任務(wù):處理3 處理完畢
用時(shí):3s
相對(duì)于之前的串行,這次的并行有效處理IO的阻塞,相當(dāng)于,串行就是占坑不用的角,并行則不管這些,你不用,先把你踹開(kāi),給有需要的人用先,這樣一腳腳的踹,效率就上一來(lái)了。
到此這篇關(guān)于golang的串行處理和并行處理實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)golang 串行處理和并行處理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
GoFrame通用類型變量gvar與interface基本使用對(duì)比
這篇文章主要為大家介紹了GoFrame通用類型變量gvar與interface基本使用對(duì)比,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06
go數(shù)據(jù)結(jié)構(gòu)和算法BitMap原理及實(shí)現(xiàn)示例
這篇文章主要為大家介紹了go數(shù)據(jù)結(jié)構(gòu)和算法BitMap原理及實(shí)現(xiàn)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07
go?micro微服務(wù)proto開(kāi)發(fā)安裝及使用規(guī)則
這篇文章主要為大家介紹了go?micro微服務(wù)proto開(kāi)發(fā)中安裝Protobuf及基本規(guī)范字段的規(guī)則詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01
golang的HTTP基本認(rèn)證機(jī)制實(shí)例詳解
這篇文章主要介紹了golang的HTTP基本認(rèn)證機(jī)制,結(jié)合實(shí)例形式較為詳細(xì)的分析了HTTP請(qǐng)求響應(yīng)的過(guò)程及認(rèn)證機(jī)制實(shí)現(xiàn)技巧,需要的朋友可以參考下2016-07-07
用Go+Redis實(shí)現(xiàn)分布式鎖的示例代碼
在分布式的業(yè)務(wù)中 , 如果有的共享資源需要安全的被訪問(wèn)和處理 , 那就需要分布式鎖,本文主要介紹了用Go+Redis實(shí)現(xiàn)分布式鎖的示例代碼,感興趣的可以了解一下2021-12-12
goland安裝1.7版本報(bào)錯(cuò)Unpacked?SDK?is?corrupted解決
這篇文章主要為大家介紹了goland安裝1.7版本報(bào)錯(cuò)Unpacked?SDK?is?corrupted解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-11-11

