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

Go語言并發(fā)編程之控制并發(fā)數(shù)量實(shí)現(xiàn)實(shí)例

 更新時間:2024年01月05日 10:28:38   作者:程序員Aike  
這篇文章主要為大家介紹了Go語言并發(fā)編程之控制并發(fā)數(shù)量實(shí)例探究,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

今天我主要分享下Go語言并發(fā)編程如何控制并發(fā)數(shù)量。

適用場景

有一批數(shù)據(jù)需要并發(fā)處理,不能開啟協(xié)程數(shù)量過多,以免服務(wù)器資源耗盡或者對服務(wù)造成過大壓力,需要控制并發(fā)數(shù)量為N。

代碼

話不多說,直接上代碼,示例中采用三種方式進(jìn)行處理。

1、以int數(shù)據(jù)集為例,并發(fā)數(shù)量為num;

2、第一種方式,并發(fā)函數(shù)報錯則終止任務(wù)執(zhí)行。后兩種方式會等待所有處理任務(wù)執(zhí)行完,再返回是否發(fā)生錯誤。

代碼如下:

# utils.go
package utils
import (
  "context"
  "fmt"
  "sync"
  "golang.org/x/sync/errgroup"
)
// BatchDeal BatchDeal
// TODO int類型待后續(xù)修改為泛型T
func BatchDeal(ctx context.Context, records []int, num int, f func(context.Context, int) error) (err error) {
  ch := make(chan int, num)
  go func() {
    select {
    case <-ctx.Done():
      return
    default:
    }
    for _, v := range records {
      ch <- v
    }
    close(ch)
  }()
  errCh := make(chan error, len(records))
  go func() {
    goN(num, func(i int) {
      select {
      case <-ctx.Done():
        errCh <- ctx.Err()
        return
      default:
      }
      for v := range ch {
        if er := f(ctx, v); er != nil {
          errCh <- er
        }
      }
    })()
    // 處理完關(guān)閉errCh
    close(errCh)
  }()
  // 有錯誤就結(jié)束或者關(guān)閉errCh后執(zhí)行
  err = <-errCh
  if err != nil {
    fmt.Printf("batch deal fail, err=%v", err)
    return
  }
  fmt.Println("batch deal end")
  return
}
func goN(n int, fn func(int)) func() {
  var wg sync.WaitGroup
  for i := 0; i < n; i++ {
    wg.Add(1)
    go func(i int) {
      fn(i)
      wg.Done()
    }(i)
  }
  return wg.Wait
}
// BatchDeal2 BatchDeal2
// TODO int類型待后續(xù)修改為泛型T
func BatchDeal2(ctx context.Context, records []int, num int, f func(context.Context, int) error) (err error) {
  ch := make(chan int, num)
  go func() {
    select {
    case <-ctx.Done():
      return
    default:
    }
    for _, v := range records {
      ch <- v
    }
    close(ch)
  }()
  err = groupN(ctx, num, func(ctx context.Context) error {
    select {
    case <-ctx.Done():
      return ctx.Err()
    default:
    }
    for v := range ch {
      if err := f(ctx, v); err != nil {
        return err
      }
    }
    return nil
  })
  if err != nil {
    fmt.Printf("batch deal fail, err=%v", err)
    return
  }
  fmt.Println("batch deal end")
  return
}
// groupN n為并發(fā)數(shù)量
func groupN(ctx context.Context, n int, fn func(context.Context) error) error {
  group, ctx := errgroup.WithContext(ctx)
  for i := 0; i < n; i++ {
    group.Go(func() error {
      if err := fn(ctx); err != nil {
        return err
      }
      return nil
    })
  }
  return group.Wait()
}
// BatchDeal3 BatchDeal3
// TODO int類型待后續(xù)修改為泛型T
func BatchDeal3(ctx context.Context, records []int, num int, f func(context.Context, int) error) (err error) {
  group, ctx := errgroup.WithContext(ctx)
  // 并發(fā)控制channel,并發(fā)數(shù)量為num
  ch := make(chan struct{}, num)
  for _, v := range records {
    // 元素進(jìn)channel,并發(fā)超過10則阻塞
    ch <- struct{}{}
    vCopy := v
    group.Go(func() error {
      // 釋放元素
      defer func() {
        <-ch
      }()
      if err := f(ctx, vCopy); err != nil {
        return err
      }
      return nil
    })
  }
  // 等待執(zhí)行完畢,全部執(zhí)行完畢才會結(jié)束
  if err = group.Wait(); err != nil {
    fmt.Printf("batch deal failed, err=%v", err)
  }
  fmt.Println("batch deal end")
  return
}
# utils_test.go
package utils
import (
  "context"
  "fmt"
  "testing"
  "time"
  "github.com/stretchr/testify/assert"
)
// TestBatchDeal
func TestBatchDeal(t *testing.T) {
  records := make([]int, 0)
  for i := 1; i < 100; i++ {
    records = append(records, i)
  }
  num := 10
  testAssert := assert.New(t)
  testF := func(ctx context.Context, i int) error {
    fmt.Printf("args=%d", i)
    time.Sleep(time.Duration(i * int(time.Millisecond)))
    return nil
  }
  testFailF := func(ctx context.Context, i int) error {
    fmt.Printf("args=%d", i)
    time.Sleep(time.Duration(i * int(time.Millisecond)))
    var er error
    if i == 10 {
      fmt.Printf("error accour, i=%d\n", i)
      er = fmt.Errorf("err=%d", i)
    }
    return er
  }
  err := BatchDeal(context.Background(), records, num, testF)
  testAssert.Nil(err)
  err2 := BatchDeal(context.Background(), records, num, testFailF)
  testAssert.ErrorContains(err2, "err")
  err3 := BatchDeal2(context.Background(), records, num, testF)
  testAssert.Nil(err3)
  err4 := BatchDeal2(context.Background(), records, num, testFailF)
  testAssert.ErrorContains(err4, "err")
  err5 := BatchDeal3(context.Background(), records, num, testF)
  testAssert.Nil(err5)
  err6 := BatchDeal3(context.Background(), records, num, testFailF)
  testAssert.ErrorContains(err6, "err")
}

以上就是Go語言并發(fā)編程之控制并發(fā)數(shù)量實(shí)現(xiàn)實(shí)例的詳細(xì)內(nèi)容,更多關(guān)于Go并發(fā)控制的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Go語言學(xué)習(xí)之函數(shù)的定義與使用詳解

    Go語言學(xué)習(xí)之函數(shù)的定義與使用詳解

    這篇文章主要為大家詳細(xì)介紹Go語言中函數(shù)的定義與使用,文中的示例代碼講解詳細(xì),對我們學(xué)習(xí)Go語言有一定幫助,需要的可以參考一下
    2022-04-04
  • Go語言高效I/O并發(fā)處理雙緩沖和Exchanger模式實(shí)例探索

    Go語言高效I/O并發(fā)處理雙緩沖和Exchanger模式實(shí)例探索

    這篇文章主要介紹了Go語言高效I/O并發(fā)處理雙緩沖和Exchanger模式實(shí)例探索,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2024-01-01
  • Golang定時器的2種實(shí)現(xiàn)方法與區(qū)別

    Golang定時器的2種實(shí)現(xiàn)方法與區(qū)別

    這篇文章主要給大家介紹了關(guān)于Golang定時器的2種實(shí)現(xiàn)方法與區(qū)別的相關(guān)資料,文中通過圖文介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-02-02
  • 使用go連接clickhouse的實(shí)戰(zhàn)操作

    使用go連接clickhouse的實(shí)戰(zhàn)操作

    這篇文章主要給大家介紹了關(guān)于使用go連接clickhouse的實(shí)戰(zhàn)操作,文中通過實(shí)例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用go具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2023-03-03
  • Go中make函數(shù)和append函數(shù)的作用詳解

    Go中make函數(shù)和append函數(shù)的作用詳解

    本文給大家介紹Go中make函數(shù)和append函數(shù)的作用詳解,本文結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2025-10-10
  • Go語言編寫高可用日志收集腳本

    Go語言編寫高可用日志收集腳本

    在分布式系統(tǒng)和微服務(wù)架構(gòu)中,日志是排查問題、審計行為、監(jiān)控狀態(tài)的重要來源,本文將編寫一個輕量級,高可用的日志收集腳本,有需要的小伙伴可以了解下
    2025-09-09
  • go select編譯期的優(yōu)化處理邏輯使用場景分析

    go select編譯期的優(yōu)化處理邏輯使用場景分析

    select 是 Go 中的一個控制結(jié)構(gòu),類似于用于通信的 switch 語句。每個 case 必須是一個通信操作,要么是發(fā)送要么是接收。接下來通過本文給大家介紹go select編譯期的優(yōu)化處理邏輯使用場景分析,感興趣的朋友一起看看吧
    2021-06-06
  • Golang對struct字段重新排序優(yōu)化數(shù)據(jù)結(jié)構(gòu)性能實(shí)踐

    Golang對struct字段重新排序優(yōu)化數(shù)據(jù)結(jié)構(gòu)性能實(shí)踐

    這篇文章主要為大家介紹了Golang對struct字段重新排序優(yōu)化數(shù)據(jù)結(jié)構(gòu)性能實(shí)踐,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-12-12
  • 一文帶你揭秘Go中new()和make()函數(shù)的區(qū)別和用途

    一文帶你揭秘Go中new()和make()函數(shù)的區(qū)別和用途

    Go(或 Golang)是一種現(xiàn)代、靜態(tài)類型、編譯型的編程語言,專為構(gòu)建可擴(kuò)展、并發(fā)和高效的軟件而設(shè)計,它提供了各種內(nèi)置的函數(shù)和特性,幫助開發(fā)人員編寫簡潔高效的代碼,在本博客文章中,我們將探討 new() 和 make() 函數(shù)之間的區(qū)別,了解何時以及如何有效地使用它們
    2023-10-10
  • Go語言中包導(dǎo)入下劃線的作用詳細(xì)解析

    Go語言中包導(dǎo)入下劃線的作用詳細(xì)解析

    這篇文章主要介紹了Go語言中包導(dǎo)入下劃線作用的相關(guān)資料,下劃線導(dǎo)入可以幫助我們更好地管理初始化邏輯,減少代碼的冗余,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2025-04-04

最新評論

伊吾县| 汉源县| 疏附县| 都安| 曲水县| 宁陵县| 临潭县| 岗巴县| 泰兴市| 旬邑县| 建水县| 大宁县| 永和县| 苗栗县| 宁波市| 阜宁县| 东海县| 武城县| 峡江县| 绥滨县| 泗阳县| 左云县| 台南市| 宁城县| 大化| 高邮市| 东乡| 达孜县| 禹城市| 张北县| 洛南县| 泰安市| 桐乡市| 广汉市| 仙桃市| 张家口市| 乡宁县| 洛宁县| 长汀县| 沿河| 中山市|