<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
做過Java開發的同學肯定知道,JDK7加入的Fork/Join是一個非常優秀的設計,到了JDK8,又結合並行流中進行了優化和增強,是一個非常好的工具。
Fork/Join本質上是一種任務分解,即:將一個很大的任務分解成若干個小任務,然後再對小任務進一步分解,直到最小顆粒度,然後並行執行。
這麼做的優點很明顯,就是可以大幅提升計算效能,缺點嘛,也有一點,那就是資源開銷要大一些。
在網上找了一張圖,任務分解就是這個意思:
對於Golang中的Fork/Join的實現,我參考了JDK的原始碼,利用了Goroutine特性,這樣就能充分利用MPG模型,不必自己再處理任務竊取等問題了,用起來還是蠻爽的。
廢話不多說,請看程式碼:
package like_fork_join import ( "fmt" "github.com/oklog/ulid/v2" ) const defaultPageSize = 10 type MyForkJoinTask struct { size int } // NewMyTask 初始化一個任務 func NewMyTask(pageSize int) *MyForkJoinTask { var size = defaultPageSize if pageSize > size { size = pageSize } return &MyForkJoinTask{ size: size, } } // Do 執行任務時,傳入一個切片 func (t *MyForkJoinTask) Do(numbers []int) int { JoinCh := make(chan bool, 1) resultCh := make(chan int, 1) t.do(numbers, JoinCh, resultCh, ulid.Make().String()) result := <-resultCh return result } func (t *MyForkJoinTask) do(numbers []int, joinCh chan bool, resultCh chan int, id string) { defer func() { joinCh <- true close(joinCh) close(resultCh) }() fmt.Printf("id %s numbers %+vn", id, numbers) // 任務小於最小顆粒度時,直接執行邏輯(此處是求和),不再拆分,否則進行分治 if len(numbers) <= t.size { var sum = 0 for _, number := range numbers { sum += number } resultCh <- sum fmt.Printf("id %s numbers %+v, result %+vn", id, numbers, sum) return } else { start := 0 end := len(numbers) middle := (start + end) / 2 // 左 leftJoinCh := make(chan bool, 1) leftResultCh := make(chan int, 1) leftId := ulid.Make().String() go t.do(numbers[start:middle], leftJoinCh, leftResultCh, id+"->left->"+leftId) // 右 rightJoinCh := make(chan bool, 1) rightResultCh := make(chan int, 1) rightId := ulid.Make().String() go t.do(numbers[middle:], rightJoinCh, rightResultCh, id+"->right->"+rightId) // 等待左邊和右邊分治子任務結束 var leftDone, rightDone = false, false for { select { case _, ok := <-leftJoinCh: if ok { fmt.Printf("left %s join donen", leftId) leftDone = true } case _, ok := <-rightJoinCh: if ok { fmt.Printf("right %s join donen", rightId) rightDone = true } } if leftDone && rightDone { break } } // 取結果 var ( left = 0 right = 0 leftResultDone = false rightResultDone = false ) for { select { case l, ok := <-leftResultCh: if ok { fmt.Printf("id %s numbers %+v, left %s return: %+vn", id, numbers, leftId, left) left = l leftResultDone = true } case r, ok := <-rightResultCh: if ok { fmt.Printf("id %s numbers %+v, right %s return: %+vn", id, numbers, rightId, right) right = r rightResultDone = true } } if leftResultDone && rightResultDone { break } } resultCh <- left + right return } }
程式碼也不復雜,有註釋,大家耐心讀一下就明白了。
我寫了一個比較有壓力的測試用例程式碼,請看:
package like_fork_join import ( "fmt" "testing" ) func TestMyTask_Do(t1 *testing.T) { type args struct { numbers []int } const max = 10000 var nums = make([]int, 0, max) var want = 0 for i := 1; i <= max; i++ { nums = append(nums, i) want += i } tests := []struct { name string args args want int }{ {name: fmt.Sprintf("sum(1,%d)", max), args: args{numbers: nums}, want: want}, } for _, tt := range tests { t1.Run(tt.name, func(t1 *testing.T) { for i := 0; i <= 100; i += 5 { t := NewMyTask(i) if got := t.Do(tt.args.numbers); got != tt.want { t1.Errorf("Do() = %v, want %v", got, tt.want) } } }) } }
測試成功:
--- PASS: TestMyTask_Do/sum(1,10000) (1257.79s) PASS
刪除所有fmt包的控制檯輸出,再跑單元測試結果:
=== RUN TestMyTask_Do
--- PASS: TestMyTask_Do (60.53s)
=== RUN TestMyTask_Do/sum(1,10000)
--- PASS: TestMyTask_Do/sum(1,10000) (60.53s)
PASS
20萬次加法計算,長度為1萬的陣列的20次計算,60秒搞定,效能巨強,Golang就是棒!
計劃後續再研究研究,看能否把執行任務的邏輯做成泛型和函數閉包,給抽象出來,這樣就能單獨形成一個通用型的程式碼包,供外部各種應用程式使用了,不過考慮到goroutine的上下文等問題,估計會讓程式碼比較複雜,眼下這個版本足夠簡單,也能滿足絕大多數場景了。
到此這篇關於Golang的Fork/Join實現的文章就介紹到這了,更多相關Golang的Fork/Join實現內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45