欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

一篇文章搞懂Go語言中的Context

 更新時(shí)間:2022年07月04日 09:36:13   作者:??BarryYan????  
這篇文章主要介紹了一篇文章搞懂Go語言中的Context,Context攜帶一個(gè)截止日期、一個(gè)取消信號(hào)和其他跨越API邊界的值。上下文的方法可以被多個(gè)gor例程同時(shí)調(diào)用

0 前置知識(shí)sync.WaitGroup

sync.WaitGroup是等待一組協(xié)程結(jié)束。它實(shí)現(xiàn)了一個(gè)類似任務(wù)隊(duì)列的結(jié)構(gòu),可以向隊(duì)列中加入任務(wù),任務(wù)完成后就把任務(wù)從隊(duì)列中移除,如果隊(duì)列中的任務(wù)沒有全部完成,隊(duì)列就會(huì)觸發(fā)阻塞以阻止程序繼續(xù)運(yùn)行。 sync.WaitGroup只有3個(gè)方法,Add(),Done(),Wait() 。

其中Done()是Add(-1)的別名,使用Add()添加計(jì)數(shù),Done()減掉一個(gè)計(jì)數(shù),計(jì)數(shù)不為0, 阻塞Wait()的運(yùn)行。

示例:

package main
import (
 ? "fmt"
 ? "sync"
 ? "time"
)
var group sync.WaitGroup
func sayHello() {
 ? for i := 0; i < 5; i++ {
 ? ? ?fmt.Println("hello......")
 ? ? ?time.Sleep(time.Second)
 ? }
 ? //線程結(jié)束 -1
 ? group.Done()
}
func sayHi() {
 ? //線程結(jié)束 -1
 ? defer group.Done()
 ? for i := 0; i < 5; i++ {
 ? ? ?fmt.Println("hi......")
 ? ? ?time.Sleep(time.Second)
 ? }
}
func main() {
 ? //+2
 ? group.Add(2)
 ? fmt.Println("main正在阻塞...")
 ? go sayHello()
 ? fmt.Println("main持續(xù)阻塞...")
 ? go sayHi()
 ? //線程等待
 ? group.Wait()
 ? fmt.Println("main貌似結(jié)束了阻塞...")
}

效果:

1 簡(jiǎn)介

在 Go 服務(wù)器中,每個(gè)傳入請(qǐng)求都在其自己的 goroutine 中處理。請(qǐng)求處理程序通常會(huì)啟動(dòng)額外的 goroutine 來訪問后端,例如數(shù)據(jù)庫和 RPC 服務(wù)。處理請(qǐng)求的一組 goroutine 通常需要訪問特定于請(qǐng)求的值,例如最終用戶的身份、授權(quán)令牌和請(qǐng)求的截止日期。當(dāng)請(qǐng)求被取消或超時(shí)時(shí),處理該請(qǐng)求的所有 goroutine 都應(yīng)該快速退出,以便系統(tǒng)可以回收它們正在使用的任何資源。

為此,開發(fā)了一個(gè)context包,可以輕松地將請(qǐng)求范圍的值、取消信號(hào)和截止日期跨 API 邊界傳遞給處理請(qǐng)求所涉及的所有 goroutine。

Context攜帶一個(gè)截止日期、一個(gè)取消信號(hào)和其他跨越API邊界的值。上下文的方法可以被多個(gè)gor例程同時(shí)調(diào)用。

對(duì)服務(wù)器的傳入請(qǐng)求應(yīng)該創(chuàng)建一個(gè)上下文,對(duì)服務(wù)器的傳出調(diào)用應(yīng)該接受一個(gè)上下文。它們之間的函數(shù)調(diào)用鏈必須傳播 Context,可選擇將其替換為使用 WithCancel、WithDeadline、WithTimeout 或 WithValue 創(chuàng)建的派生 Context。當(dāng)一個(gè)上下文被取消時(shí),所有從它派生的上下文也被取消。

WithCancel、WithDeadline 和 WithTimeout 函數(shù)采用 Context(父)并返回派生的 Context(子)和 CancelFunc。調(diào)用 CancelFunc 會(huì)取消子項(xiàng)及其子項(xiàng),刪除父項(xiàng)對(duì)子項(xiàng)的引用,并停止任何關(guān)聯(lián)的計(jì)時(shí)器。調(diào)用 CancelFunc 失敗會(huì)泄漏子項(xiàng)及其子項(xiàng),直到父項(xiàng)被取消或計(jì)時(shí)器觸發(fā)。go vet 工具檢查是否在所有控制流路徑上使用了 CancelFuncs。

使用上下文的程序應(yīng)遵循以下規(guī)則,以保持跨包的接口一致,并啟用靜態(tài)分析工具來檢查上下文傳播:

不要將上下文存儲(chǔ)在結(jié)構(gòu)類型中;相反,將 Context 顯式傳遞給需要它的每個(gè)函數(shù)。

Context 應(yīng)該是第一個(gè)參數(shù),通常命名為 ctx:

func DoSomething(ctx context.Context, arg Arg) error { 
    // ... 使用 ctx ... 
}

即使函數(shù)允許,也不要傳遞 nil 上下文。如果不確定要使用哪個(gè) Context,請(qǐng)傳遞 context.TODO。

僅將上下文值用于傳輸流程和 API 的請(qǐng)求范圍數(shù)據(jù),而不用于將可選參數(shù)傳遞給函數(shù)。

相同的 Context 可以傳遞給在不同的 goroutine 中運(yùn)行的函數(shù);上下文對(duì)于多個(gè) goroutine 同時(shí)使用是安全的。

2 context.Context引入

//上下文攜帶截止日期、取消信號(hào)和請(qǐng)求范圍的值在API的界限。它的方法是安全的同時(shí)使用多個(gè)了goroutine。
type Context interface {
 ? ?// Done返回一個(gè)在上下文被取消或超時(shí)時(shí)關(guān)閉的通道。
 ? ?Done() <-chan struct{}
?
 ? ?// Err表示在Done通道關(guān)閉后為何取消此上下文。
 ? ?Err() error
?
 ? ?// Deadline返回上下文將被取消的時(shí)間(如果有的話)。
 ? ?Deadline() (deadline time.Time, ok bool)
?
 ? ?// Value返回與key相關(guān)的值,如果沒有則返回nil。
 ? ?Value(key interface{}) interface{}
}
  • Done方法返回一個(gè)通道,該通道作為代表運(yùn)行的函數(shù)的取消信號(hào)Context:當(dāng)通道關(guān)閉時(shí),函數(shù)應(yīng)該放棄它們的工作并返回。
  • Err方法返回一個(gè)錯(cuò)誤,指示Context取消的原因。
  • 一個(gè)Context對(duì)于多個(gè) goroutine 同時(shí)使用是安全的。代碼可以將單個(gè)傳遞Context給任意數(shù)量的 goroutines 并取消它Context以向所有g(shù)oroutine 發(fā)出信號(hào)。
  • Deadline方法允許函數(shù)確定它們是否應(yīng)該開始工作,還可以使用截止日期來設(shè)置 I/O 操作的超時(shí)時(shí)間。
  • Value允許一個(gè)Context攜帶請(qǐng)求范圍的數(shù)據(jù)。該數(shù)據(jù)必須是安全的,以便多個(gè) goroutine 同時(shí)使用。

3 context包的其他常用函數(shù)

3.1 context.Background和context.TODO

Background是任何Context樹的根,它永遠(yuǎn)不會(huì)被取消:

//Background返回一個(gè)空的Context。 它永遠(yuǎn)不會(huì)取消,沒有截止日期,沒有價(jià)值。 Background通常用于main、init和tests,并作為傳入請(qǐng)求的頂級(jí)上下文。 ?
func Background() Context

給一個(gè)函數(shù)方法傳遞Context的時(shí)候,不要傳遞nil,如果不知道傳遞什么,就使用context.TODO()

3.2 context.WithCancel和

WithCancelt返回派生的Context值,可以比父Context更快地取消。當(dāng)請(qǐng)求處理程序返回時(shí),通常會(huì)取消與傳入請(qǐng)求關(guān)聯(lián)的content。當(dāng)使用多個(gè)副本時(shí),WithCancel對(duì)于取消冗余請(qǐng)求也很有用。

// WithCancel返回一個(gè)父進(jìn)程的副本,該父進(jìn)程的Done通道被盡快關(guān)閉。?關(guān)閉Done或調(diào)用cancel。
func WithCancel(parent Context) (ctx Context, cancel CancelFunc)
// CancelFunc取消一個(gè)上下文。
type CancelFunc func()

示例:

package main
import (
 ? "context"
 ? "fmt"
)
func play(ctx context.Context) <-chan int {
 ? dist := make(chan int)
 ? n := 1
 ? //匿名函數(shù) 向dist中加入元素
 ? go func() {
 ? ? ?for {
 ? ? ? ? select {
 ? ? ? ? //ctx為空時(shí)將不會(huì)執(zhí)行這個(gè)
 ? ? ? ? case <-ctx.Done():
 ? ? ? ? ? ?return // return結(jié)束該goroutine,防止泄露
 ? ? ? ? ? ?//向dist中加入元素
 ? ? ? ? case dist <- n:
 ? ? ? ? ? ?n++
 ? ? ? ? }
 ? ?  }
 ? }()
 ? return dist
}
func main() {
 ? //返回空的context
 ? ctx, cancel := context.WithCancel(context.Background())
 ? defer cancel() // 調(diào)用cancel
 ? for n := range play(ctx) {
 ? ? ?fmt.Println(n)
 ? ? ?if n == 5 {
 ? ? ? ? break
 ? ?  }
 ? }
}

擴(kuò)展:go中select的用法

```
select的用法與switch語言非常類似,由select開始一個(gè)新的選擇塊,每個(gè)選擇條件由case語句來描述。
與switch語句相比, select有比較多的限制,其中最大的一條限制就是每個(gè)case語句里必須是一個(gè)IO操作,大致的結(jié)構(gòu)如下:
``` go
select {
 ? case <-chan1:
 ? ? ?// 如果chan1成功讀到數(shù)據(jù),則進(jìn)行該case處理語句
 ? case chan2 <- 1:
 ? ? ?// 如果成功向chan2寫入數(shù)據(jù),則進(jìn)行該case處理語句
 ? default:
 ? ? ?// 如果上面都沒有成功,則進(jìn)入default處理流程
}
```
在一個(gè)select語句中,Go語言會(huì)按順序從頭至尾評(píng)估每一個(gè)發(fā)送和接收的語句。
如果其中的任意一語句可以繼續(xù)執(zhí)行(即沒有被阻塞),那么就從那些可以執(zhí)行的語句中任意選擇一條來使用。
如果沒有任意一條語句可以執(zhí)行(即所有的通道都被阻塞),那么有兩種可能的情況:
- 如果給出了default語句,那么就會(huì)執(zhí)行default語句,同時(shí)程序的執(zhí)行會(huì)從select語句后的語句中恢復(fù)。
- 如果沒有default語句,那么select語句將被阻塞,直到至少有一個(gè)通信可以進(jìn)行下去。
```

3.3 context.WithTimeout

WithTimeout返回派生的Context值,WithTimeout用于設(shè)置請(qǐng)求到后端服務(wù)器的截止日期:

//WithTimeout返回一個(gè)父進(jìn)程的副本,該父進(jìn)程的Done通道被立即關(guān)閉的父母。關(guān)閉“完成”、調(diào)用“取消”或超時(shí)結(jié)束。新
//Context的Deadline是現(xiàn)在的更快+timeout和父的Deadline,如果任何。?如果計(jì)時(shí)器仍然在運(yùn)行,則cancel函數(shù)釋放它資源。
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)
// CancelFunc取消一個(gè)上下文。
type CancelFunc func()

示例:

package main
import (
 ? "context"
 ? "fmt"
 ? "sync"
 ? "time"
)
var wg sync.WaitGroup
func worker(ctx context.Context) {
 ? ?LOOP:
 ? for {
 ? ? ?fmt.Println("db connecting ...")
 ? ? ?time.Sleep(time.Millisecond * 10) // 假設(shè)正常連接數(shù)據(jù)庫耗時(shí)10毫秒
 ? ? ?select {
 ? ? ?case <-ctx.Done(): // 50毫秒后自動(dòng)調(diào)用
 ? ? ? ? break LOOP
 ? ? ?default:
 ? ?  }
 ? }
 ? fmt.Println("worker done!")
 ? wg.Done()
}
func main() {
 ? // 設(shè)置一個(gè)50毫秒的超時(shí)
 ? ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*50)
 ? wg.Add(1)
 ? go worker(ctx)
 ? time.Sleep(time.Second * 5)
 ? cancel() // 通知子goroutine結(jié)束
 ? wg.Wait()
 ? fmt.Println("over")
}

執(zhí)行結(jié)果:

3.4 context.WithDeadline

func WithDeadline(parent Context, d time.Time) (Context, CancelFunc) {
 ? if parent == nil {
 ? ? ?panic("cannot create context from nil parent")
 ? }
 ? if cur, ok := parent.Deadline(); ok && cur.Before(d) {
 ? ? ?// 目前的期限已經(jīng)比新的期限提前
 ? ? ?return WithCancel(parent)
 ? }
 ? c := &timerCtx{
 ? ? ?cancelCtx: newCancelCtx(parent),
 ? ? ?deadline: ?d,
 ? }
 ? propagateCancel(parent, c)
 ? dur := time.Until(d)
 ? if dur <= 0 {
 ? ? ?c.cancel(true, DeadlineExceeded) // 截止日期已經(jīng)過去了
 ? ? ?return c, func() { c.cancel(false, Canceled) }
 ? }
 ? c.mu.Lock()
 ? defer c.mu.Unlock()
 ? if c.err == nil {
 ? ? ?c.timer = time.AfterFunc(dur, func() {
 ? ? ? ? c.cancel(true, DeadlineExceeded)
 ? ?  })
 ? }
 ? return c, func() { c.cancel(true, Canceled) }
}

示例:

package main
import (
 ? "context"
 ? "fmt"
 ? "time"
)
func main() {
 ? d := time.Now().Add(500 * time.Millisecond)
 ? ctx, cancel := context.WithDeadline(context.Background(), d)
 ? // 盡管ctx會(huì)過期,但在任何情況下調(diào)用它的cancel函數(shù)都是很好的實(shí)踐。
 ? // 如果不這樣做,可能會(huì)使上下文及其父類存活的時(shí)間超過必要的時(shí)間。
 ? defer cancel()
 ? select {
 ? case <-time.After(1 * time.Second):
 ? ? ?fmt.Println("over")
 ? case <-ctx.Done():
 ? ? ?fmt.Println(ctx.Err())
 ? }
}

執(zhí)行結(jié)果:

3.5 context.WithValue

WithValue提供了一種將請(qǐng)求范圍的值與Context關(guān)聯(lián)的方法 :

//WithValue返回父元素的副本,其Value方法返回val for key。
func WithValue(parent Context, key interface{}, val interface{}) Context

了解如何使用context包的最好方法是通過一個(gè)已工作的示例。

示例:

package main
import (
 ? "context"
 ? "fmt"
 ? "sync"
 ? "time"
)
type TraceCode string
var wg sync.WaitGroup
func worker(ctx context.Context) {
 ? key := TraceCode("KEY_CODE")
 ? traceCode, ok := ctx.Value(key).(string) // 在子goroutine中獲取trace code
 ? if !ok {
 ? ? ?fmt.Println("invalid trace code")
 ? }
 ? ?LOOP:
 ? for {
 ? ? ?fmt.Printf("worker,code:%s\n", traceCode)
 ? ? ?time.Sleep(time.Millisecond * 10) // 假設(shè)正常連接數(shù)據(jù)庫耗時(shí)10毫秒
 ? ? ?select {
 ? ? ?case <-ctx.Done(): // 50毫秒后自動(dòng)調(diào)用
 ? ? ? ? break LOOP
 ? ? ?default:
 ? ?  }
 ? }
 ? fmt.Println("worker is over!")
 ? wg.Done()
}
?
func main() {
 ? // 設(shè)置一個(gè)50毫秒的超時(shí)
 ? ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*50)
 ? // 在系統(tǒng)的入口中設(shè)置trace code傳遞給后續(xù)啟動(dòng)的goroutine實(shí)現(xiàn)日志數(shù)據(jù)聚合
 ? ctx = context.WithValue(ctx, TraceCode("KEY_CODE"), "12512312234")
 ? wg.Add(1)
 ? go worker(ctx)
 ? time.Sleep(time.Second * 5)
 ? cancel() // 通知子goroutine結(jié)束
 ? wg.Wait()
 ? fmt.Println("over")
}

執(zhí)行結(jié)果:

4 實(shí)例:請(qǐng)求瀏覽器超時(shí)

server端:

package main
import (
 ? "fmt"
 ? "math/rand"
 ? "net/http"
 ? "time"
)
// server端,隨機(jī)出現(xiàn)慢響應(yīng)
func indexHandler(w http.ResponseWriter, r *http.Request) {
 ? number := rand.Intn(2)
 ? if number == 0 {
 ? ? ?time.Sleep(time.Second * 10) // 耗時(shí)10秒的慢響應(yīng)
 ? ? ?fmt.Fprintf(w, "slow response")
 ? ? ?return
 ? }
 ? fmt.Fprint(w, "quick response")
}
func main() {
 ? http.HandleFunc("/", indexHandler)
 ? err := http.ListenAndServe(":9999", nil)
 ? if err != nil {
 ? ? ?panic(err)
 ? }
}

client端:

package main
import (
 ? "context"
 ? "fmt"
 ? "io/ioutil"
 ? "net/http"
 ? "sync"
 ? "time"
)
// 客戶端
?
type respData struct {
 ? resp *http.Response
 ? err ?error
}
func doCall(ctx context.Context) {
 ? // http長連接
 ? transport := http.Transport{DisableKeepAlives: true}
 ? client := http.Client{Transport: &transport}
?
 ? respChan := make(chan *respData, 1)
 ? req, err := http.NewRequest("GET", "http://127.0.0.1:9999/", nil)
 ? if err != nil {
 ? ? ?fmt.Println(err)
 ? ? ?return
 ? }
 ? req = req.WithContext(ctx) // 使用帶超時(shí)的ctx創(chuàng)建一個(gè)新的client request
 ? var wg sync.WaitGroup
 ? wg.Add(1)
 ? defer wg.Wait()
 ? go func() {
 ? ? ?resp, err := client.Do(req)
 ? ? ?fmt.Printf("resp:%v, err:%v\n", resp, err)
 ? ? ?rd := &respData{
 ? ? ? ? resp: resp,
 ? ? ? ? err: ?err,
 ? ?  }
 ? ? ?respChan <- rd
 ? ? ?wg.Done()
 ? }()
 ? select {
 ? case <-ctx.Done():
 ? ? ?fmt.Println("timeout...")
 ? case result := <-respChan:
 ? ? ?fmt.Println("success....")
 ? ? ?if result.err != nil {
 ? ? ? ? fmt.Printf("err:%v\n", result.err)
 ? ? ? ? return
 ? ?  }
 ? ? ?defer result.resp.Body.Close()
 ? ? ?data, _ := ioutil.ReadAll(result.resp.Body)
 ? ? ?fmt.Printf("resp:%v\n", string(data))
 ? }
}
?
func main() {
 ? // 定義一個(gè)100毫秒的超時(shí)
 ? ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*100)
 ? defer cancel() // 調(diào)用cancel釋放子goroutine資源
 ? doCall(ctx)
}

5 Context包都在哪些地方使用

許多服務(wù)器框架提供了用于承載請(qǐng)求作用域值的包和類型。我們可以定義“Context”接口的新實(shí)現(xiàn),在使用現(xiàn)有框架的代碼和需要“Context”參數(shù)的代碼之間架起橋梁。

6 小結(jié)

在谷歌中,要求Go程序員將“Context”參數(shù)作為傳入和傳出請(qǐng)求之間的調(diào)用路徑上的每個(gè)函數(shù)的第一個(gè)參數(shù)傳遞。這使得許多不同團(tuán)隊(duì)開發(fā)的Go代碼能夠很好地互操作。它提供了對(duì)超時(shí)和取消的簡(jiǎn)單控制,并確保像安全憑證這樣的關(guān)鍵值能夠正確地傳輸Go程序。

想要構(gòu)建在“Context”上的服務(wù)器框架應(yīng)該提供“Context”的實(shí)現(xiàn)來連接它們的包和那些需要“Context”參數(shù)的包。然后,它們的客戶端庫將接受來自調(diào)用代碼的“Context”。通過為請(qǐng)求范圍的數(shù)據(jù)和取消建立一個(gè)公共接口,“上下文”使包開發(fā)人員更容易共享創(chuàng)建可伸縮服務(wù)的代碼。

到此這篇關(guān)于一篇文章搞懂Go語言中的Context的文章就介紹到這了,更多相關(guān) Go Context內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 一文教你如何快速學(xué)會(huì)Go的切片和數(shù)組數(shù)據(jù)類型

    一文教你如何快速學(xué)會(huì)Go的切片和數(shù)組數(shù)據(jù)類型

    數(shù)組是屬于同一類型的元素的集合。切片是數(shù)組頂部的方便、靈活且功能強(qiáng)大的包裝器。本文就來和大家聊聊Go中切片和數(shù)組的使用,需要的可以參考一下
    2023-03-03
  • Golang中channel的原理解讀(推薦)

    Golang中channel的原理解讀(推薦)

    channel主要是為了實(shí)現(xiàn)go的并發(fā)特性,用于并發(fā)通信的,也就是在不同的協(xié)程單元goroutine之間同步通信。接下來通過本文給大家介紹Golang中channel的原理解讀,感興趣的朋友一起看看吧
    2021-10-10
  • go獲取協(xié)程(goroutine)號(hào)的實(shí)例

    go獲取協(xié)程(goroutine)號(hào)的實(shí)例

    這篇文章主要介紹了go獲取協(xié)程(goroutine)號(hào)的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-12-12
  • GoLand一鍵上傳項(xiàng)目到遠(yuǎn)程服務(wù)器的方法步驟

    GoLand一鍵上傳項(xiàng)目到遠(yuǎn)程服務(wù)器的方法步驟

    我們開發(fā)項(xiàng)目常常將項(xiàng)目上傳到linux遠(yuǎn)程服務(wù)器上來運(yùn)行,本文主要介紹了GoLand一鍵上傳項(xiàng)目到遠(yuǎn)程服務(wù)器的方法步驟,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-06-06
  • Go語言超時(shí)退出的三種實(shí)現(xiàn)方式總結(jié)

    Go語言超時(shí)退出的三種實(shí)現(xiàn)方式總結(jié)

    這篇文章主要為大家詳細(xì)介紹了Go語言中超時(shí)退出的三種實(shí)現(xiàn)方式,文中的示例代碼簡(jiǎn)潔易懂,對(duì)我們深入了解Go語言有一定的幫助,需要的可以了解一下
    2023-06-06
  • 淺談golang 中time.After釋放的問題

    淺談golang 中time.After釋放的問題

    這篇文章主要介紹了淺談golang 中time.After釋放的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-05-05
  • Golang嵌入資源文件實(shí)現(xiàn)步驟詳解

    Golang嵌入資源文件實(shí)現(xiàn)步驟詳解

    在應(yīng)用程序中附帶代碼以外的其他資源可能會(huì)很有用,常用的實(shí)現(xiàn)方法是嵌入對(duì)象或數(shù)據(jù)。在數(shù)據(jù)庫中存儲(chǔ)數(shù)據(jù)應(yīng)用中,需要定義schema,在應(yīng)用啟動(dòng)時(shí)創(chuàng)建表,但如果找不到schema文件呢?Go1.16提供embed包讓實(shí)現(xiàn)變得簡(jiǎn)單,之前很多第三方包實(shí)現(xiàn)類似功能
    2023-01-01
  • GoFrame?glist?基礎(chǔ)使用和自定義遍歷

    GoFrame?glist?基礎(chǔ)使用和自定義遍歷

    這篇文章主要為大家介紹了GoFrame?glist的基礎(chǔ)使用和自定義遍歷示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06
  • Golang Goroutine的使用

    Golang Goroutine的使用

    這篇文章主要介紹了Golang Goroutine的使用,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-10-10
  • Go與C語言的互操作實(shí)現(xiàn)

    Go與C語言的互操作實(shí)現(xiàn)

    在Go與C語言互操作方面,Go更是提供了強(qiáng)大的支持。尤其是在Go中使用C,你甚至可以直接在Go源文件中編寫C代碼,本文就詳細(xì)的介紹一下如何使用,感興趣的可以了解一下
    2021-12-12

最新評(píng)論