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

Go并發(fā)編程實踐

 更新時間:2017年01月24日 22:24:53   投稿:mdxy-dxy  
并發(fā)編程一直是Golang區(qū)別與其他語言的很大優(yōu)勢,也是實際工作場景中經(jīng)常遇到的。近日筆者在組內(nèi)分享了我們常見的并發(fā)場景,及代碼示例,以期望大家能在遇到相同場景下,能快速的想到解決方案,或者是拿這些方案與自己實現(xiàn)的比較,取長補短?,F(xiàn)整理出來與大家共享

前言

并發(fā)編程一直是Golang區(qū)別與其他語言的很大優(yōu)勢,也是實際工作場景中經(jīng)常遇到的。近日筆者在組內(nèi)分享了我們常見的并發(fā)場景,及代碼示例,以期望大家能在遇到相同場景下,能快速的想到解決方案,或者是拿這些方案與自己實現(xiàn)的比較,取長補短。現(xiàn)整理出來與大家共享。

簡單并發(fā)場景

很多時候,我們只想并發(fā)的做一件事情,比如測試某個接口的是否支持并發(fā)。那么我們就可以這么做:

func RunScenario1() {
    count := 10
    var wg sync.WaitGroup

    for i := 0; i < count; i++ {
       wg.Add(1)
       go func(index int) {
           defer wg.Done()
           doSomething(index)
       }(i)
    }

    wg.Wait()
}

使用goroutine來實現(xiàn)異步,使用WaitGroup來等待所有g(shù)oroutine結(jié)束。這里要注意的是要正確釋放WaitGroup的counter(在goroutine里調(diào)用Done()方法)。

但此種方式有個弊端,就是當(dāng)goroutine的量過多時,很容易消耗完客戶端的資源,導(dǎo)致程序表現(xiàn)不佳。

規(guī)定時間內(nèi)的持續(xù)并發(fā)模型

我們?nèi)匀灰詼y試某個后端API接口為例,如果我們想知道這個接口在持續(xù)高并發(fā)情況下是否有句柄泄露,這種情況該如何測試呢?

這種時候,我們需要能控制時間的高并發(fā)模型:

func RunScenario2() {
  timeout := time.Now().Add(time.Second * time.Duration(10))
  n := runtime.NumCPU()

  waitForAll := make(chan struct{})
  done := make(chan struct{})
  concurrentCount := make(chan struct{}, n)

  for i := 0; i < n; i++ {
    concurrentCount <- struct{}{}
  }

  go func() {
    for time.Now().Before(timeout) {
      <-done
      concurrentCount <- struct{}{}
    }

    waitForAll <- struct{}{}
  }()

  go func() {
    for {
      <-concurrentCount
      go func() {
        doSomething(rand.Intn(n))
        done <- struct{}{}
      }()
    }
  }()

  <-waitForAll
}

上面的代碼里,我們通過一個buffered channel來控制并發(fā)的數(shù)量(concurrentCount),然后另起一個channel來周期性的發(fā)起新的任務(wù),而控制的條件就是 time.Now().Before(timeout),這樣當(dāng)超過規(guī)定的時間,waitForAll 就會得到信號,而使整個程序退出。

這是一種實現(xiàn)方式,那么還有其他的方式?jīng)]?我們接著往下看。

基于大數(shù)據(jù)量的并發(fā)模型

前面說的基于時間的并發(fā)模型,那如果只知道數(shù)據(jù)量很大,但是具體結(jié)束時間不確定,該怎么辦呢?

比如,客戶給了個幾TB的文件列表,要求把這些文件從存儲里刪除。再比如,實現(xiàn)個爬蟲去爬某些網(wǎng)站的所有內(nèi)容。

而解決此類問題,最常見的就是使用工作池模式了(Worker Pool)。以刪文件為例,我們可以簡單這樣來處理:

Jobs - 可以從文件列表里讀取文件,初始化為任務(wù),然后發(fā)給worker
Worker - 拿到任務(wù)開始做事
Collector - 收集worker處理后的結(jié)果
Worker Pool - 控制并發(fā)的數(shù)量

雖然這只是個簡單Worker Pool模型,但已經(jīng)能滿足我們的需求:

func RunScenario3() {
    numOfConcurrency := runtime.NumCPU()
    taskTool := 10
    jobs := make(chan int, taskTool)
    results := make(chan int, taskTool)
    var wg sync.WaitGroup

    // workExample
    workExampleFunc := func(id int, jobs <-chan int, results chan<- int, wg *sync.WaitGroup) {
       defer wg.Done()
       for job := range jobs {
           res := job * 2
           fmt.Printf("Worker %d do things, produce result %d \n", id, res)
           time.Sleep(time.Millisecond * time.Duration(100))
           results <- res
       }
    }

    for i := 0; i < numOfConcurrency; i++ {
       wg.Add(1)
       go workExampleFunc(i, jobs, results, &wg)
    }

    totalTasks := 100 // 本例就要從文件列表里讀取

    wg.Add(1)
    go func() {
       defer wg.Done()
       for i := 0; i < totalTasks; i++ {
           n := <-results
           fmt.Printf("Got results %d \n", n)
       }
       close(results)
    }()

    for i := 0; i < totalTasks; i++ {
       jobs <- i
    }
    close(jobs)
    wg.Wait()
}

在Go里,分發(fā)任務(wù),收集結(jié)果,我們可以都交給Channel來實現(xiàn)。從實現(xiàn)上更加的簡潔。

仔細(xì)看會發(fā)現(xiàn),本模型也是適用于按時間來控制并發(fā)。只要把totalTask的遍歷換成時間控制就好了。

等待異步任務(wù)執(zhí)行結(jié)果

goroutine和channel的組合在實際編程時經(jīng)常會用到,而加上Select更是無往而不利。

func RunScenario4() {
    sth := make(chan string)
    result := make(chan string)
    go func() {
       id := rand.Intn(100)
       for {
           sth <- doSomething(id)
       }
    }()
    go func() {
       for {
           result <- takeSomthing(<-sth)
       }
    }()

    select {
    case c := <-result:
       fmt.Printf("Got result %s ", c)
    case <-time.After(time.Duration(30 * time.Second)):
       fmt.Errorf("指定時間內(nèi)都沒有得到結(jié)果")
    }
}

在select的case情況,加上time.After()模型可以讓我們在一定時間范圍內(nèi)等待異步任務(wù)結(jié)果,防止程序卡死。

定時反饋異步任務(wù)結(jié)果

上面我們說到持續(xù)的壓測某后端API,但并未實時收集結(jié)果。而很多時候?qū)τ谛阅軠y試場景,實時的統(tǒng)計吞吐率,成功率是非常有必要的。

func RunScenario5() {
  concurrencyCount := runtime.NumCPU()
  for i := 0; i < concurrencyCount; i++ {
    go func(index int) {
      for {
        doUploadMock()
      }
    }(i)
  }

  t := time.NewTicker(time.Second)
  for {
    select {
    case <-t.C:
      // 計算并打印實時數(shù)據(jù)
    }
  } 
}

這種場景就需要使用到Ticker,且上面的Example模型還能控制并發(fā)數(shù)量,也是非常實用的方式。

知識點總結(jié)

上面我們共提到了五種并發(fā)模式:

  • 簡單并發(fā)模型
  • 規(guī)定時間內(nèi)的持續(xù)并發(fā)模型
  • 基于大數(shù)據(jù)量的持續(xù)并發(fā)模型
  • 等待異步任務(wù)結(jié)果模型
  • 定時反饋異步任務(wù)結(jié)果模型

歸納下來其核心就是使用了Go的幾個知識點:Goroutine, Channel, Select, Time, Timer/Ticker, WaitGroup. 若是對這些不清楚,可以自行Google之。

另完整的Example 代碼可以參考這里:https://github.com/jichangjun/golearn/blob/master/src/carlji.com/experiments/concurrency/main.go

使用方式: go run main.go <場景>

比如 :

參考文檔

https://github.com/golang/go/wiki/LearnConcurrency
這篇是Google官方推薦學(xué)習(xí)Go并發(fā)的資料,從初學(xué)者到進(jìn)階,內(nèi)容非常豐富,且權(quán)威。

Contact me ?

Email: jinsdu@outlook.com

Blog: http://www.cnblogs.com/jinsdu/

Github: https://github.com/CarlJi

相關(guān)文章

  • golang讀取http的body時遇到的坑及解決

    golang讀取http的body時遇到的坑及解決

    這篇文章主要介紹了golang讀取http的body時遇到的坑及解決方案,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-03-03
  • golang http使用踩過的坑與應(yīng)對方式

    golang http使用踩過的坑與應(yīng)對方式

    這篇文章主要介紹了golang http使用踩過的坑與應(yīng)對方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • go語言寫的簡要數(shù)據(jù)同步工具詳解

    go語言寫的簡要數(shù)據(jù)同步工具詳解

    作為go-etl工具的作者,想要安利一下這個小巧的數(shù)據(jù)同步工具,它在同步百萬級別的數(shù)據(jù)時表現(xiàn)極為優(yōu)異,基本能在幾分鐘完成數(shù)據(jù)同步,這篇文章主要介紹了go語言寫的簡要數(shù)據(jù)同步工具,需要的朋友可以參考下
    2024-07-07
  • Go語言關(guān)于幾種深度拷貝(deepcopy)方法的性能對比

    Go語言關(guān)于幾種深度拷貝(deepcopy)方法的性能對比

    這篇文章主要介紹了Go語言關(guān)于幾種深度拷貝(deepcopy)方法的性能對比,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • go?mongox簡潔高效文檔操作及bson數(shù)據(jù)構(gòu)造流暢技巧

    go?mongox簡潔高效文檔操作及bson數(shù)據(jù)構(gòu)造流暢技巧

    這篇文章主要為大家介紹了go?mongox簡潔高效文檔操作及bson數(shù)據(jù)構(gòu)造流暢技巧示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-11-11
  • Go調(diào)度器學(xué)習(xí)之協(xié)作與搶占詳解

    Go調(diào)度器學(xué)習(xí)之協(xié)作與搶占詳解

    如果某個G執(zhí)行時間過長,其他的G如何才能被正常調(diào)度,這就引出了接下來的話題:協(xié)作與搶占。本文將通過一些示例為大家詳細(xì)講講調(diào)度器中協(xié)作與搶占的相關(guān)知識,需要的可以參考一下
    2023-04-04
  • Golang處理parquet文件實戰(zhàn)指南

    Golang處理parquet文件實戰(zhàn)指南

    這篇文章主要給大家介紹了關(guān)于Golang處理parquet文件的相關(guān)資料,文中通過實例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用Golang具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2023-03-03
  • 一文帶你了解Go語言中的I/O接口設(shè)計

    一文帶你了解Go語言中的I/O接口設(shè)計

    I/O?操作在編程中扮演著至關(guān)重要的角色,它涉及程序與外部世界之間的數(shù)據(jù)交換,下面我們就來簡單了解一下Go語言中的?I/O?接口設(shè)計吧
    2023-06-06
  • golang中的三個點 ''...''的用法示例詳解

    golang中的三個點 ''...''的用法示例詳解

    這篇文章主要介紹了golang中的三個點 '...' 的用法示例詳解,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-11-11
  • go日志系統(tǒng)logrus顯示文件和行號的操作

    go日志系統(tǒng)logrus顯示文件和行號的操作

    這篇文章主要介紹了go日志系統(tǒng)logrus顯示文件和行號的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-11-11

最新評論

玛多县| 娄烦县| 于田县| 石柱| 宁海县| 镇巴县| 永康市| 达日县| 新乐市| 多伦县| 连城县| 柘城县| 金乡县| 仁怀市| 岳池县| 云安县| 利川市| 济南市| 娄底市| 松滋市| 遂昌县| 闽清县| 搜索| 阜阳市| 平和县| 绥中县| 曲周县| 六盘水市| 堆龙德庆县| 桂东县| 明水县| 九江市| 寻甸| 贡嘎县| 望谟县| 嫩江县| 九龙城区| 永平县| 廉江市| 江源县| 梓潼县|