最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Golang的Fork/Join實現(xiàn)代碼

 更新時間:2023年01月15日 15:25:45   作者:互聯(lián)網(wǎng)速遞520  
Fork/Join本質(zhì)上是一種任務(wù)分解,將一個很大的任務(wù)分解成若干個小任務(wù),然后再對小任務(wù)進一步分解,直到最小顆粒度,然后并發(fā)執(zhí)行,對Golang的Fork/Join實現(xiàn)代碼感興趣的朋友跟隨小編一起看看吧

做過Java開發(fā)的同學(xué)肯定知道,JDK7加入的Fork/Join是一個非常優(yōu)秀的設(shè)計,到了JDK8,又結(jié)合并行流中進行了優(yōu)化和增強,是一個非常好的工具。

1、Fork/Join是什么

Fork/Join本質(zhì)上是一種任務(wù)分解,即:將一個很大的任務(wù)分解成若干個小任務(wù),然后再對小任務(wù)進一步分解,直到最小顆粒度,然后并發(fā)執(zhí)行。

這么做的優(yōu)點很明顯,就是可以大幅提升計算性能,缺點嘛,也有一點,那就是資源開銷要大一些。

在網(wǎng)上找了一張圖,任務(wù)分解就是這個意思:

2、Golang中的Fork/Join實現(xiàn)

對于Golang中的Fork/Join的實現(xiàn),我參考了JDK的源碼,利用了Goroutine特性,這樣就能充分利用MPG模型,不必自己再處理任務(wù)竊取等問題了,用起來還是蠻爽的。

廢話不多說,請看代碼:

package like_fork_join
 
import (
    "fmt"
    "github.com/oklog/ulid/v2"
)
 
const defaultPageSize = 10
 
type MyForkJoinTask struct {
    size int
}
 
// NewMyTask 初始化一個任務(wù)
func NewMyTask(pageSize int) *MyForkJoinTask {
    var size = defaultPageSize
    if pageSize > size {
        size = pageSize
    }
    return &MyForkJoinTask{
        size: size,
    }
}
 
// Do 執(zhí)行任務(wù)時,傳入一個切片
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 %+v\n", id, numbers)
    // 任務(wù)小于最小顆粒度時,直接執(zhí)行邏輯(此處是求和),不再拆分,否則進行分治
    if len(numbers) <= t.size {
        var sum = 0
        for _, number := range numbers {
            sum += number
        }
        resultCh <- sum
        fmt.Printf("id %s numbers %+v, result %+v\n", 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)
 
        // 等待左邊和右邊分治子任務(wù)結(jié)束
        var leftDone, rightDone = false, false
        for {
            select {
            case _, ok := <-leftJoinCh:
                if ok {
                    fmt.Printf("left %s join done\n", leftId)
                    leftDone = true
                }
            case _, ok := <-rightJoinCh:
                if ok {
                    fmt.Printf("right %s join done\n", rightId)
                    rightDone = true
                }
            }
            if leftDone && rightDone {
                break
            }
        }
 
        // 取結(jié)果
        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: %+v\n", id, numbers, leftId, left)
                    left = l
                    leftResultDone = true
                }
            case r, ok := <-rightResultCh:
                if ok {
                    fmt.Printf("id %s numbers %+v, right %s return: %+v\n", id, numbers, rightId, right)
                    right = r
                    rightResultDone = true
                }
            }
            if leftResultDone && rightResultDone {
                break
            }
        }
 
        resultCh <- left + right
        return
    }
}

代碼也不復(fù)雜,有注釋,大家耐心讀一下就明白了。

3、測試驗證

我寫了一個比較有壓力的測試用例代碼,請看:

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

4、小優(yōu)化

刪除所有fmt包的控制臺輸出,再跑單元測試結(jié)果:

=== 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萬的數(shù)組的20次計算,60秒搞定,性能巨強,Golang就是棒!

5、后續(xù)計劃

計劃后續(xù)再研究研究,看能否把執(zhí)行任務(wù)的邏輯做成泛型和函數(shù)閉包,給抽象出來,這樣就能單獨形成一個通用型的代碼包,供外部各種應(yīng)用程序使用了,不過考慮到goroutine的上下文等問題,估計會讓代碼比較復(fù)雜,眼下這個版本足夠簡單,也能滿足絕大多數(shù)場景了。

到此這篇關(guān)于Golang的Fork/Join實現(xiàn)的文章就介紹到這了,更多相關(guān)Golang的Fork/Join實現(xiàn)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Golang棧結(jié)構(gòu)和后綴表達式實現(xiàn)計算器示例

    Golang棧結(jié)構(gòu)和后綴表達式實現(xiàn)計算器示例

    這篇文章主要為大家介紹了Golang棧結(jié)構(gòu)和后綴表達式實現(xiàn)計算器示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-07-07
  • Go語言實戰(zhàn)之詳細掌握正則表達式的應(yīng)用與技巧

    Go語言實戰(zhàn)之詳細掌握正則表達式的應(yīng)用與技巧

    正則表達式是一種從左到右與主題字符串匹配的模式,正則表達式用于替換字符串中的文本,驗證表單,基于模式匹配從字符串中提取子字符串等等,這篇文章主要給大家介紹了關(guān)于Go語言實戰(zhàn)之詳細掌握正則表達式的應(yīng)用與技巧,需要的朋友可以參考下
    2023-12-12
  • 詳解Go語言中如何高效遍歷目錄

    詳解Go語言中如何高效遍歷目錄

    目錄遍歷是一個很常見的操作,它的使用場景有如文件目錄查看、文件系統(tǒng)清理、日志分析、項目構(gòu)建等,本文將詳細介紹在Go中幾種遍歷目錄文件的方法,需要的可以參考下
    2024-02-02
  • Golang使用Gin實現(xiàn)文件上傳的示例代碼

    Golang使用Gin實現(xiàn)文件上傳的示例代碼

    本文我們主要介紹了Golang如何使用Gin實現(xiàn)文件上傳,Go標(biāo)準(zhǔn)庫net/http對文件上傳已經(jīng)提供了非常完善的支持,而Gin框架在其基礎(chǔ)上進一步封裝,因此使用Gin開發(fā)文件上傳功能時,只需要簡單幾行代碼便可以實現(xiàn),需要的朋友可以參考下
    2024-02-02
  • golang中context的作用詳解

    golang中context的作用詳解

    這篇文章主要介紹了golang中context的作用,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-01-01
  • Golang 發(fā)送http請求時設(shè)置header的實現(xiàn)

    Golang 發(fā)送http請求時設(shè)置header的實現(xiàn)

    這篇文章主要介紹了Golang 發(fā)送http請求時設(shè)置header的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-02-02
  • golang定時器和超時的使用詳解

    golang定時器和超時的使用詳解

    這篇文章主要介紹了golang定時器和超時的使用詳解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • Go?語言前綴樹實現(xiàn)敏感詞檢測

    Go?語言前綴樹實現(xiàn)敏感詞檢測

    這篇文章主要為大家介紹了Go語言前綴樹實現(xiàn)敏感詞檢測實例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-08-08
  • 淺談Golang的Work Stealing機制

    淺談Golang的Work Stealing機制

    Go的運行時系統(tǒng)使用了一種名為Work Stealing的調(diào)度策略來分配Goroutine到可用線程上執(zhí)行,本文主要介紹了淺談Golang的Work Stealing機制,具有一定的參考價值,感興趣的可以了解一下
    2025-03-03
  • Go語言框架快速集成限流中間件詳解

    Go語言框架快速集成限流中間件詳解

    這篇文章主要為大家介紹了Go語言框架快速集成限流中間件詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-09-09

最新評論

靖安县| 礼泉县| 通渭县| 光山县| 庆安县| 应用必备| 西充县| 阳高县| 周口市| 邓州市| 桑植县| 湖南省| 涟源市| 镇平县| 永泰县| 洞头县| 抚顺市| 武川县| 乌什县| 大兴区| 喀喇| 固始县| 竹山县| 黔西县| 嘉兴市| 屏东市| 昌都县| 田林县| 嘉善县| 清水县| 邵阳县| 余姚市| 西藏| 沾益县| 永新县| 友谊县| 乌兰浩特市| 旬阳县| 荆州市| 简阳市| 四子王旗|