亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

go 熔斷原理分析與源碼解讀

 更新時(shí)間:2022年08月31日 11:30:17   作者:萬俊峰Kevin  
這篇文章主要為大家介紹了go 熔斷原理分析與源碼解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

正文

熔斷機(jī)制(Circuit Breaker)指的是在股票市場的交易時(shí)間中,當(dāng)價(jià)格的波動(dòng)幅度達(dá)到某一個(gè)限定的目標(biāo)(熔斷點(diǎn))時(shí),對其暫停交易一段時(shí)間的機(jī)制。此機(jī)制如同保險(xiǎn)絲在電流過大時(shí)候熔斷,故而得名。熔斷機(jī)制推出的目的是為了防范系統(tǒng)性風(fēng)險(xiǎn),給市場更多的冷靜時(shí)間,避免恐慌情緒蔓延導(dǎo)致整個(gè)市場波動(dòng),從而防止大規(guī)模股價(jià)下跌現(xiàn)象的發(fā)生。

同樣的,在高并發(fā)的分布式系統(tǒng)設(shè)計(jì)中,也應(yīng)該有熔斷的機(jī)制。熔斷一般是在客戶端(調(diào)用端)進(jìn)行配置,當(dāng)客戶端向服務(wù)端發(fā)起請求的時(shí)候,服務(wù)端的錯(cuò)誤不斷地增多,這時(shí)候就可能會(huì)觸發(fā)熔斷,觸發(fā)熔斷后客戶端的請求不再發(fā)往服務(wù)端,而是在客戶端直接拒絕請求,從而可以保護(hù)服務(wù)端不會(huì)過載。這里說的服務(wù)端可能是rpc服務(wù),http服務(wù),也可能是mysql,redis等。注意熔斷是一種有損的機(jī)制,當(dāng)熔斷后可能需要一些降級(jí)的策略進(jìn)行配合。

熔斷原理

現(xiàn)代微服務(wù)架構(gòu)基本都是分布式的,整個(gè)分布式系統(tǒng)是由非常多的微服務(wù)組成。不同服務(wù)之間相互調(diào)用,組成復(fù)雜的調(diào)用鏈路。在復(fù)雜的調(diào)用鏈路中的某一個(gè)服務(wù)如果不穩(wěn)定,就可能會(huì)層層級(jí)聯(lián),最終可能導(dǎo)致整個(gè)鏈路全部掛掉。因此我們需要對不穩(wěn)定的服務(wù)依賴進(jìn)行熔斷降級(jí),暫時(shí)切斷不穩(wěn)定的服務(wù)調(diào)用,避免局部不穩(wěn)定因素導(dǎo)致整個(gè)分布式系統(tǒng)的雪崩。

說白了,我覺得熔斷就像是那些容易異常服務(wù)的一種代理,這個(gè)代理能夠記錄最近調(diào)用發(fā)生錯(cuò)誤的次數(shù),然后決定是繼續(xù)操作,還是立即返回錯(cuò)誤。

熔斷器內(nèi)部維護(hù)了一個(gè)熔斷器狀態(tài)機(jī),狀態(tài)機(jī)的轉(zhuǎn)換關(guān)系如下圖所示:

熔斷器有三種狀態(tài):

  • Closed狀態(tài):也是初始狀態(tài),我們需要一個(gè)調(diào)用失敗的計(jì)數(shù)器,如果調(diào)用失敗,則使失敗次數(shù)加1。如果最近失敗次數(shù)超過了在給定時(shí)間內(nèi)允許失敗的閾值,則切換到Open狀態(tài),此時(shí)開啟一個(gè)超時(shí)時(shí)鐘,當(dāng)?shù)竭_(dá)超時(shí)時(shí)鐘時(shí)間后,則切換到Half Open狀態(tài),該超時(shí)時(shí)間的設(shè)定是給了系統(tǒng)一次機(jī)會(huì)來修正導(dǎo)致調(diào)用失敗的錯(cuò)誤,以回到正常的工作狀態(tài)。在Closed狀態(tài)下,錯(cuò)誤計(jì)數(shù)是基于時(shí)間的。在特定的時(shí)間間隔內(nèi)會(huì)自動(dòng)重置,這能夠防止由于某次的偶然錯(cuò)誤導(dǎo)致熔斷器進(jìn)入Open狀態(tài),也可以基于連續(xù)失敗的次數(shù)。
  • Open狀態(tài):在該狀態(tài)下,客戶端請求會(huì)立即返回錯(cuò)誤響應(yīng),而不調(diào)用服務(wù)端。
  • Half-Open狀態(tài):允許客戶端一定數(shù)量的去調(diào)用服務(wù)端,如果這些請求對服務(wù)的調(diào)用成功,那么可以認(rèn)為之前導(dǎo)致調(diào)用失敗的錯(cuò)誤已經(jīng)修正,此時(shí)熔斷器切換到Closed狀態(tài),同時(shí)將錯(cuò)誤計(jì)數(shù)器重置。如果這一定數(shù)量的請求有調(diào)用失敗的情況,則認(rèn)為導(dǎo)致之前調(diào)用失敗的的問題仍然存在,熔斷器切回到斷開狀態(tài),然后重置計(jì)時(shí)器來給系統(tǒng)一定的時(shí)間來修正錯(cuò)誤。Half-Open狀態(tài)能夠有效防止正在恢復(fù)中的服務(wù)被突然而來的大量請求再次打掛。

下圖是Netflix的開源項(xiàng)目Hystrix中的熔斷器的實(shí)現(xiàn)邏輯:

從這個(gè)流程圖中,可以看到:

  • 有請求來了,首先allowRequest()函數(shù)判斷是否在熔斷中,如果不是則放行,如果是的話,還要看有沒有達(dá)到一個(gè)熔斷時(shí)間片,如果熔斷時(shí)間片到了,也放行,否則直接返回錯(cuò)誤。
  • 每次調(diào)用都有兩個(gè)函數(shù)makeSuccess(duration)和makeFailure(duration)來統(tǒng)計(jì)一下在一定的duration內(nèi)有多少是成功還是失敗的。
  • 判斷是否熔斷的條件isOpen(),是計(jì)算failure/(success+failure)當(dāng)前的錯(cuò)誤率,如果高于一個(gè)閾值,那么熔斷器打開,否則關(guān)閉。
  • Hystrix會(huì)在內(nèi)存中維護(hù)一個(gè)數(shù)據(jù),其中記錄著每一個(gè)周期的請求結(jié)果的統(tǒng)計(jì),超過時(shí)長長度的元素會(huì)被刪除掉。

熔斷器實(shí)現(xiàn)

了解了熔斷的原理后,我們來自己實(shí)現(xiàn)一套熔斷器。

熟悉go-zero的朋友都知道,在go-zero中熔斷沒有采用上面介紹的方式,而是參考了《Google Sre》 采用了一種自適應(yīng)的熔斷機(jī)制,這種自適應(yīng)的方式有什么好處呢?下文會(huì)基于這兩種機(jī)制做一個(gè)對比。

下面我們基于上面介紹的熔斷原理,實(shí)現(xiàn)一套自己的熔斷器。

代碼路徑:go-zero/core/breaker/hystrixbreaker.go

熔斷器默認(rèn)的狀態(tài)為Closed,當(dāng)熔斷器打開后默認(rèn)的冷卻時(shí)間是5秒鐘,當(dāng)熔斷器處于HalfOpen狀態(tài)時(shí)默認(rèn)的探測時(shí)間為200毫秒,默認(rèn)使用rateTripFunc方法來判斷是否觸發(fā)熔斷,規(guī)則是采樣大于等于200且錯(cuò)誤率大于50%,使用滑動(dòng)窗口來記錄請求總數(shù)和錯(cuò)誤數(shù)。

func newHystrixBreaker() *hystrixBreaker {
  bucketDuration := time.Duration(int64(window) / int64(buckets))
  stat := collection.NewRollingWindow(buckets, bucketDuration)
  return &hystrixBreaker{
    state:          Closed,
    coolingTimeout: defaultCoolingTimeout,
    detectTimeout:  defaultDetectTimeout,
    tripFunc:       rateTripFunc(defaultErrRate, defaultMinSample),
    stat:           stat,
    now:            time.Now,
  }
}
func rateTripFunc(rate float64, minSamples int64) TripFunc {
  return func(rollingWindow *collection.RollingWindow) bool {
    var total, errs int64
    rollingWindow.Reduce(func(b *collection.Bucket) {
      total += b.Count
      errs += int64(b.Sum)
    })
    errRate := float64(errs) / float64(total)
    return total >= minSamples && errRate > rate
  }
}

每次請求都會(huì)調(diào)用doReq方法,在該方法中,首先通過accept()方法判斷是否拒絕本次請求,拒絕則直接返回熔斷錯(cuò)誤。否則執(zhí)行req()真正的發(fā)起服務(wù)端調(diào)用,成功和失敗分別調(diào)用b.markSuccess()和b.markFailure()

func (b *hystrixBreaker) doReq(req func() error, fallback func(error) error, acceptable Acceptable) error {
  if err := b.accept(); err != nil {
    if fallback != nil {
      return fallback(err)
    }
    return err
  }
  defer func() {
    if e := recover(); e != nil {
      b.markFailure()
      panic(e)
    }
  }()
  err := req()
  if acceptable(err) {
    b.markSuccess()
  } else {
    b.markFailure()
  }
  return err
}

在accept()方法中,首先獲取當(dāng)前熔斷器狀態(tài),當(dāng)熔斷器處于Closed狀態(tài)直接返回,表示正常處理本次請求。

當(dāng)前狀態(tài)為Open的時(shí)候,判斷冷卻時(shí)間是否過期,如果沒有過期的話則直接返回熔斷錯(cuò)誤拒絕本次請求,如果過期的話則把熔斷器狀態(tài)更改為HalfOpen,冷卻時(shí)間的主要目的是給服務(wù)端一些時(shí)間進(jìn)行故障恢復(fù),避免持續(xù)請求把服務(wù)端打掛。

當(dāng)前狀態(tài)為HalfOpen的時(shí)候,首先判斷探測時(shí)間間隔,避免探測過于頻繁,默認(rèn)使用200毫秒作為探測間隔。

func (b *hystrixBreaker) accept() error {
  b.mux.Lock()
  switch b.getState() {
  case Open:
    now := b.now()
    if b.openTime.Add(b.coolingTimeout).After(now) {
      b.mux.Unlock()
      return ErrServiceUnavailable
    }
    if b.getState() == Open {
      atomic.StoreInt32((*int32)(&b.state), int32(HalfOpen))
      atomic.StoreInt32(&b.halfopenSuccess, 0)
      b.lastRetryTime = now
      b.mux.Unlock()
    } else {
      b.mux.Unlock()
      return ErrServiceUnavailable
    }
  case HalfOpen:
    now := b.now()
    if b.lastRetryTime.Add(b.detectTimeout).After(now) {
      b.mux.Unlock()
      return ErrServiceUnavailable
    }
    b.lastRetryTime = now
    b.mux.Unlock()
  case Closed:
    b.mux.Unlock()
  }
  return nil
}

如果本次請求正常返回,則調(diào)用markSuccess()方法,如果當(dāng)前熔斷器處于HalfOpen狀態(tài),則判斷當(dāng)前探測成功數(shù)量是否大于默認(rèn)的探測成功數(shù)量,如果大于則把熔斷器的狀態(tài)更新為Closed。

func (b *hystrixBreaker) markSuccess() {
  b.mux.Lock()
  switch b.getState() {
  case Open:
    b.mux.Unlock()
  case HalfOpen:
    atomic.AddInt32(&b.halfopenSuccess, 1)
    if atomic.LoadInt32(&b.halfopenSuccess) > defaultHalfOpenSuccesss {
      atomic.StoreInt32((*int32)(&b.state), int32(Closed))
      b.stat.Reduce(func(b *collection.Bucket) {
        b.Count = 0
        b.Sum = 0
      })
    }
    b.mux.Unlock()
  case Closed:
    b.stat.Add(1)
    b.mux.Unlock()
  }
}

在markFailure()方法中,如果當(dāng)前狀態(tài)是Closed通過執(zhí)行tripFunc來判斷是否滿足熔斷條件,如果滿足則把熔斷器狀態(tài)更改為Open狀態(tài)。

func (b *hystrixBreaker) markFailure() {
  b.mux.Lock()
  b.stat.Add(0)
  switch b.getState() {
  case Open:
    b.mux.Unlock()
  case HalfOpen:
    b.openTime = b.now()
    atomic.StoreInt32((*int32)(&b.state), int32(Open))
    b.mux.Unlock()
  case Closed:
    if b.tripFunc != nil && b.tripFunc(b.stat) {
      b.openTime = b.now()
      atomic.StoreInt32((*int32)(&b.state), int32(Open))
    }
    b.mux.Unlock()
  }
}

熔斷器的實(shí)現(xiàn)邏輯總體比較簡單,閱讀代碼基本都能理解,這部分代碼實(shí)現(xiàn)的比較倉促,可能會(huì)有bug,如果大家發(fā)現(xiàn)bug可以隨時(shí)聯(lián)系我進(jìn)行修正。

hystrixBreaker和googlebreaker對比

接下來對比一下兩種熔斷器的熔斷效果。

這部分示例代碼在:go-zero/example下

分別定義了user-api和user-rpc服務(wù),user-api作為客戶端對user-rpc進(jìn)行請求,user-rpc作為服務(wù)端響應(yīng)客戶端請求。

在user-rpc的示例方法中,有20%的幾率返回錯(cuò)誤。

func (l *UserInfoLogic) UserInfo(in *user.UserInfoRequest) (*user.UserInfoResponse, error) {
  ts := time.Now().UnixMilli()
  if in.UserId == int64(1) {
    if ts%5 == 1 {
      return nil, status.Error(codes.Internal, "internal error")
    }
    return &user.UserInfoResponse{
      UserId: 1,
      Name:   "jack",
    }, nil
  }
  return &user.UserInfoResponse{}, nil
}

在user-api的示例方法中,對user-rpc發(fā)起請求,然后使用prometheus指標(biāo)記錄正常請求的數(shù)量。

var metricSuccessReqTotal = metric.NewCounterVec(&metric.CounterVecOpts{
  Namespace: "circuit_breaker",
  Subsystem: "requests",
  Name:      "req_total",
  Help:      "test for circuit breaker",
  Labels:    []string{"method"},
})
func (l *UserInfoLogic) UserInfo() (resp *types.UserInfoResponse, err error) {
  for {
    _, err := l.svcCtx.UserRPC.UserInfo(l.ctx, &user.UserInfoRequest{UserId: int64(1)})
    if err != nil && err == breaker.ErrServiceUnavailable {
      fmt.Println(err)
      continue
    }
    metricSuccessReqTotal.Inc("UserInfo")
  }
  return &types.UserInfoResponse{}, nil
}

啟動(dòng)兩個(gè)服務(wù),然后觀察在兩種熔斷策略下正常請求的數(shù)量。

googleBreaker熔斷器的正常請求率如下圖所示:

hystrixBreaker熔斷器的正常請求率如下圖所示:

從上面的實(shí)驗(yàn)結(jié)果可以看出,go-zero內(nèi)置的googleBreaker的正常請求數(shù)是高于hystrixBreaker的。這是因?yàn)閔ystrixBreaker維護(hù)了三種狀態(tài),當(dāng)進(jìn)入Open狀態(tài)后為了避免繼續(xù)對服務(wù)端發(fā)起請求造成壓力,會(huì)使用一個(gè)冷卻時(shí)鐘,而在這段時(shí)間里是不會(huì)放過任何請求的,同時(shí),從HalfOpen狀態(tài)變?yōu)镃losed狀態(tài)后,瞬間又會(huì)有大量的請求發(fā)往服務(wù)端,這時(shí)服務(wù)端很可能還沒恢復(fù),從而導(dǎo)致熔斷器又變?yōu)镺pen狀態(tài)。

而googleBreaker采用的是一種自適應(yīng)的熔斷策略,也不需要多種狀態(tài),也不會(huì)像hystrixBreaker那樣一刀切,而是會(huì)盡可能多的處理請求,這不也是我們期望的嘛,畢竟熔斷對客戶來說是有損的。下面我們來一起學(xué)習(xí)下go-zero內(nèi)置的熔斷器googleBreaker。

源碼解讀

googleBreaker的代碼路徑在:go-zero/core/breaker/googlebreaker.go

在doReq()方法中通過accept()方法判斷是否觸發(fā)熔斷,如果觸發(fā)熔斷則返回error,這里如果定義了回調(diào)函數(shù)的話可以執(zhí)行回調(diào),比如做一些降級(jí)數(shù)據(jù)的處理等。如果請求正常則通過markSuccess()給總請求數(shù)和正常請求數(shù)都加1,如果請求失敗通過markFailure則只給總請求數(shù)加1。

func (b *googleBreaker) doReq(req func() error, fallback func(err error) error, acceptable Acceptable) error {
  if err := b.accept(); err != nil {
    if fallback != nil {
      return fallback(err)
    }
    return err
  }
  defer func() {
    if e := recover(); e != nil {
      b.markFailure()
      panic(e)
    }
  }()
  err := req()
  if acceptable(err) {
    b.markSuccess()
  } else {
    b.markFailure()
  }
  return err
}

在accept()方法中通過計(jì)算判斷是否觸發(fā)熔斷。

在該算法中,需要記錄兩個(gè)請求數(shù),分別是:

  • 請求總量(requests): 調(diào)用方發(fā)起請求的數(shù)量總和
  • 正常處理的請求數(shù)量(accepts): 服務(wù)端正常處理的請求數(shù)量

在正常情況下,這兩個(gè)值是相等的,隨著被調(diào)用方服務(wù)出現(xiàn)異常開始拒絕請求,請求接受數(shù)量(accepts)的值開始逐漸小于請求數(shù)量(requests),這個(gè)時(shí)候調(diào)用方可以繼續(xù)發(fā)送請求,直到requests = K * accepts,一旦超過這個(gè)限制,熔斷器就會(huì)打開,新的請求會(huì)在本地以一定的概率被拋棄直接返回錯(cuò)誤,概率的計(jì)算公式如下:

max(0, (requests - K * accepts) / (requests + 1))

通過修改算法中的K(倍值),可以調(diào)節(jié)熔斷器的敏感度,當(dāng)降低該倍值會(huì)使自適應(yīng)熔斷算法更敏感,當(dāng)增加該倍值會(huì)使得自適應(yīng)熔斷算法降低敏感度,舉例來說,假設(shè)將調(diào)用方的請求上限從 requests = 2 acceptst 調(diào)整為 requests = 1.1 accepts 那么就意味著調(diào)用方每十個(gè)請求之中就有一個(gè)請求會(huì)觸發(fā)熔斷。

func (b *googleBreaker) accept() error {
  accepts, total := b.history()
  weightedAccepts := b.k * float64(accepts)
  // https://landing.google.com/sre/sre-book/chapters/handling-overload/#eq2101
  dropRatio := math.Max(0, (float64(total-protection)-weightedAccepts)/float64(total+1))
  if dropRatio <= 0 {
    return nil
  }
  if b.proba.TrueOnProba(dropRatio) {
    return ErrServiceUnavailable
  }
  return nil
}

history從滑動(dòng)窗口中統(tǒng)計(jì)當(dāng)前的總請求數(shù)和正常處理的請求數(shù)。

func (b *googleBreaker) history() (accepts, total int64) {
  b.stat.Reduce(func(b *collection.Bucket) {
    accepts += int64(b.Sum)
    total += b.Count
  })
  return
}

結(jié)束語

本篇文章介紹了服務(wù)治理中的一種客戶端節(jié)流機(jī)制 - 熔斷。在hystrix熔斷策略中需要實(shí)現(xiàn)三個(gè)狀態(tài),分別是Open、HalfOpen和Closed。不同狀態(tài)的切換時(shí)機(jī)在上文中也有詳細(xì)描述,大家可以反復(fù)閱讀理解,最好是能自己動(dòng)手實(shí)現(xiàn)一下。對于go-zero內(nèi)置的熔斷器是沒有狀態(tài)的,如果非要說它的狀態(tài)的話,那么也只有打開和關(guān)閉兩種情況,它是根據(jù)當(dāng)前請求的成功率自適應(yīng)的丟棄請求,是一種更彈性的熔斷策略,丟棄請求概率隨著正常處理的請求數(shù)不斷變化,正常處理的請求越多丟棄請求的概率就越低,反之丟棄請求的概率就越高。

雖然熔斷的原理都一樣,但實(shí)現(xiàn)機(jī)制不同導(dǎo)致的效果可能也不同,在實(shí)際生產(chǎn)中可以根據(jù)實(shí)際情況選擇符合業(yè)務(wù)場景的熔斷策略。

希望本篇文章對你有所幫助。

本篇文章代碼:github.com/zhoushuguan…

參考

martinfowler.com/bliki/Circu…

github.com/Netflix/Hys…

項(xiàng)目地址

github.com/zeromicro/g…

以上就是go 熔斷原理分析與源碼解讀的詳細(xì)內(nèi)容,更多關(guān)于go 熔斷原理的資料請關(guān)注腳本之家其它相關(guān)文章!

您可能感興趣的文章:

相關(guān)文章

  • Golang?使用os?庫的?ReadFile()?讀文件最佳實(shí)踐

    Golang?使用os?庫的?ReadFile()?讀文件最佳實(shí)踐

    這篇文章主要介紹了Golang使用os庫的ReadFile()讀文件最佳實(shí)踐,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下
    2022-09-09
  • GoLang?channel關(guān)閉狀態(tài)相關(guān)操作詳解

    GoLang?channel關(guān)閉狀態(tài)相關(guān)操作詳解

    Channel?和?goroutine?的結(jié)合是?Go?并發(fā)編程的大殺器。而?Channel?的實(shí)際應(yīng)用也經(jīng)常讓人眼前一亮,通過與?select,cancel,timer?等結(jié)合,它能實(shí)現(xiàn)各種各樣的功能。接下來,我們就要介紹GoLang?channel關(guān)閉狀態(tài)相關(guān)操作
    2022-10-10
  • Golang使用cobra實(shí)現(xiàn)命令行程序的示例代碼

    Golang使用cobra實(shí)現(xiàn)命令行程序的示例代碼

    Cobra 是 Go 語言中一個(gè)強(qiáng)大的命令行應(yīng)用庫,它提供了創(chuàng)建命令行工具所需的基本結(jié)構(gòu)和功能,被許多開發(fā)者用于構(gòu)建各種命令行工具和應(yīng)用程序,本文將給大家介紹Golang使用cobra實(shí)現(xiàn)命令行程序,文中通過代碼示例介紹的非常詳細(xì),需要的朋友可以參考下
    2024-02-02
  • Go 語言單例模式示例詳解

    Go 語言單例模式示例詳解

    這篇文章主要為大家介紹了Go 語言單例模式示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-10-10
  • go項(xiàng)目中環(huán)境變量的配置

    go項(xiàng)目中環(huán)境變量的配置

    本文主要介紹了go項(xiàng)目中環(huán)境變量的配置,文中通過示例代碼介紹的非常詳細(xì),需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-07-07
  • Golang使用Gin創(chuàng)建Restful API的實(shí)現(xiàn)

    Golang使用Gin創(chuàng)建Restful API的實(shí)現(xiàn)

    本文主要介紹了Golang使用Gin創(chuàng)建Restful API的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-01-01
  • Golang程序漏洞檢測器govulncheck的安裝和使用

    Golang程序漏洞檢測器govulncheck的安裝和使用

    govulncheck 是一個(gè)命令行工具,可以幫助 Golang 開發(fā)者快速找到項(xiàng)目代碼和依賴的模塊中的安全漏洞,該工具可以分析源代碼和二進(jìn)制文件,識(shí)別代碼中對這些漏洞的任何直接或間接調(diào)用,本文就給大家介紹一下govulncheck安裝和使用,需要的朋友可以參考下
    2023-09-09
  • go for range遍歷二維數(shù)組的示例

    go for range遍歷二維數(shù)組的示例

    今天小編就為大家分享一篇關(guān)于go for range遍歷二維數(shù)組的示例,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2019-04-04
  • Golang利用channel協(xié)調(diào)協(xié)程的方法詳解

    Golang利用channel協(xié)調(diào)協(xié)程的方法詳解

    go?當(dāng)中的并發(fā)編程是通過goroutine來實(shí)現(xiàn)的,利用channel(管道)可以在協(xié)程之間傳遞數(shù)據(jù),所以本文就來講講Golang如何利用channel協(xié)調(diào)協(xié)程吧
    2023-05-05
  • Golang實(shí)現(xiàn)KV存儲(chǔ)引擎實(shí)例探究

    Golang實(shí)現(xiàn)KV存儲(chǔ)引擎實(shí)例探究

    這篇文章主要為大家介紹了Golang實(shí)現(xiàn)KV存儲(chǔ)引擎實(shí)例探究,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2024-01-01

最新評論