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

golang中context的作用詳解

 更新時(shí)間:2021年01月08日 14:24:10   作者:夢(mèng)回故里  
這篇文章主要介紹了golang中context的作用,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

當(dāng)一個(gè)goroutine可以啟動(dòng)其他goroutine,而這些goroutine可以啟動(dòng)其他goroutine,依此類推,則第一個(gè)goroutine應(yīng)該能夠向所有其它goroutine發(fā)送取消信號(hào)。

上下文包的唯一目的是在goroutine之間執(zhí)行取消信號(hào),而不管它們?nèi)绾紊?。上下文的接口定義為:

type Context interface {
 Deadline() (deadline time.Time, ok bool)
 Done() <- chan struct{}
 Err() error
 Value(key interface{}) interface{}
}
  • Deadline:第一個(gè)值是截止日期,此時(shí)上下文將自動(dòng)觸發(fā)“取消”操作。第二個(gè)值是布爾值,true表示設(shè)置了截止日期,false表示未設(shè)置截止時(shí)間。如果沒(méi)有設(shè)置截止日期,則必須手動(dòng)調(diào)用cancel函數(shù)來(lái)取消上下文。
  • Done:返回一個(gè)只讀通道(僅在取消后),鍵入struct {},當(dāng)該通道可讀時(shí),表示父上下文已經(jīng)發(fā)起了取消請(qǐng)求,根據(jù)此信號(hào),開(kāi)發(fā)人員可以執(zhí)行一些清除操作,退出goroutine
  • Err:返回取消上下文的原因
  • Value:返回綁定到上下文的值,它是一個(gè)鍵值對(duì),因此您需要傳遞一個(gè)Key來(lái)獲取相應(yīng)的值,此值是線程安全的

要?jiǎng)?chuàng)建上下文,必須指定父上下文。兩個(gè)內(nèi)置上下文(背景和待辦事項(xiàng))用作頂級(jí)父上下文:

var (
 background = new(emptyCtx)
 todo = new(emptyCtx)
)
func Background() Context {
 return background
}
func TODO() Context {
 return todo
}

背景,主要ü在主函數(shù),初始化和測(cè)試代碼的sed,是樹(shù)結(jié)構(gòu)中,根上下文,這是不能被取消的頂層語(yǔ)境。TODO,當(dāng)您不知道要使用什么上下文時(shí),可以使用它。它們本質(zhì)上都是emptyCtx類型,都是不可取消的,沒(méi)有固定的期限,也沒(méi)有為Context賦任何值:鍵入emptyCtx int

type emptyCtx int
func (_ *emptyCtx) Deadline() (deadline time.Time, ok bool) {
 return
}
func (_ *emptyCtx) Done() <- chan struct{} {
 return nil
}
func (_ *emptyCtx) Err() error {
 return nil
}
func (*emptyCtx) Value(key interface{}) interface{} {
 return nil
}

上下文包還具有幾個(gè)常用功能:func WithCancel(父上下文)(ctx上下文,取消CancelFunc)func WithDeadline(父上下文,截止時(shí)間.Time)(上下文,CancelFunc)func WithTimeout(父上下文,超時(shí)時(shí)間。持續(xù)時(shí)間)(上下文,CancelFunc)func WithValue(父上下文,鍵,val接口{})上下文

請(qǐng)注意,這些方法意味著可以一次繼承上下文以實(shí)現(xiàn)其他功能,例如,使用WithCancel函數(shù)傳入根上下文,它會(huì)創(chuàng)建一個(gè)子上下文,該子上下文具有取消上下文的附加功能,然后使用此方法將context(context01)作為父上下文,并將其作為第一個(gè)參數(shù)傳遞給WithDeadline函數(shù),與子context(context01)相比,獲得子context(context02),它具有一個(gè)附加功能,可在之后自動(dòng)取消上下文最后期限。

WithCancel

對(duì)于通道,盡管通道也可以通知許多嵌套的goroutine退出,但通道不是線程安全的,而上下文是線程安全的。

例如:

package main
import (
 "runtime"
 "fmt"
 "time"
 "context"
)
func monitor2(ch chan bool, index int) {
 for {
  select {
  case v := <- ch:
   fmt.Printf("monitor2: %v, the received channel value is: %v, ending\n", index, v)
   return
  default:
   fmt.Printf("monitor2: %v in progress...\n", index)
   time.Sleep(2 * time.Second)
  }
 }
}
func monitor1(ch chan bool, index int) {
 for {
  go monitor2(ch, index)
  select {
  case v := <- ch:
   // this branch is only reached when the ch channel is closed, or when data is sent(either true or false)
   fmt.Printf("monitor1: %v, the received channel value is: %v, ending\n", index, v)
   return
  default:
   fmt.Printf("monitor1: %v in progress...\n", index)
   time.Sleep(2 * time.Second)
  }
 }
}
func main() {
 var stopSingal chan bool = make(chan bool, 0)
 for i := 1; i <= 5; i = i + 1 {
  go monitor1(stopSingal, i)
 }
 time.Sleep(1 * time.Second)
 // close all gourtines
 cancel()
 // waiting 10 seconds, if the screen does not display <monitorX: xxxx in progress...>, all goroutines have been shut down
 time.Sleep(10 * time.Second)
 println(runtime.NumGoroutine())
 println("main program exit!!!!")
}

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

monitor1: 5 in progress...
monitor2: 5 in progress...
monitor1: 2 in progress...
monitor2: 2 in progress...
monitor2: 1 in progress...
monitor1: 1 in progress...
monitor1: 4 in progress...
monitor1: 3 in progress...
monitor2: 4 in progress...
monitor2: 3 in progress...
monitor1: 4, the received channel value is: false, ending
monitor1: 3, the received channel value is: false, ending
monitor2: 2, the received channel value is: false, ending
monitor2: 1, the received channel value is: false, ending
monitor1: 1, the received channel value is: false, ending
monitor2: 5, the received channel value is: false, ending
monitor2: 3, the received channel value is: false, ending
monitor2: 3, the received channel value is: false, ending
monitor2: 4, the received channel value is: false, ending
monitor2: 5, the received channel value is: false, ending
monitor2: 1, the received channel value is: false, ending
monitor1: 5, the received channel value is: false, ending
monitor1: 2, the received channel value is: false, ending
monitor2: 2, the received channel value is: false, ending
monitor2: 4, the received channel value is: false, ending
1
main program exit!!!!

這里使用一個(gè)通道向所有g(shù)oroutine發(fā)送結(jié)束通知,但是這里的情況相對(duì)簡(jiǎn)單,如果在一個(gè)復(fù)雜的項(xiàng)目中,假設(shè)多個(gè)goroutine有某種錯(cuò)誤并重復(fù)執(zhí)行,則可以重復(fù)關(guān)閉或關(guān)閉該通道通道,然后向其寫入值,從而觸發(fā)運(yùn)行時(shí)恐慌。這就是為什么我們使用上下文來(lái)避免這些問(wèn)題的原因,以WithCancel為例:

package main
import (
 "runtime"
 "fmt"
 "time"
 "context"
)
func monitor2(ctx context.Context, number int) {
 for {
  select {
  case v := <- ctx.Done():
   fmt.Printf("monitor: %v, the received channel value is: %v, ending\n", number,v)
   return
  default:
   fmt.Printf("monitor: %v in progress...\n", number)
   time.Sleep(2 * time.Second)
  }
 }
}
func monitor1(ctx context.Context, number int) {
 for {
  go monitor2(ctx, number)
  select {
  case v := <- ctx.Done():
   // this branch is only reached when the ch channel is closed, or when data is sent(either true or false)
   fmt.Printf("monitor: %v, the received channel value is: %v, ending\n", number, v)
   return
  default:
   fmt.Printf("monitor: %v in progress...\n", number)
   time.Sleep(2 * time.Second)
  }
 }
}
func main() {
 var ctx context.Context = nil
 var cancel context.CancelFunc = nil
 ctx, cancel = context.WithCancel(context.Background())
 for i := 1; i <= 5; i = i + 1 {
  go monitor1(ctx, i)
 }
 time.Sleep(1 * time.Second)
 // close all gourtines
 cancel()
 // waiting 10 seconds, if the screen does not display <monitor: xxxx in progress>, all goroutines have been shut down
 time.Sleep(10 * time.Second)
 println(runtime.NumGoroutine())
 println("main program exit!!!!")
}

WithTimeout和WithDeadline

WithTimeout和WithDeadline在用法和功能上基本相同,它們都表示上下文將在一定時(shí)間后自動(dòng)取消,唯一的區(qū)別可以從函數(shù)的定義中看出,傳遞給WithDeadline的第二個(gè)參數(shù)是類型time.Duration類型,它是一個(gè)相對(duì)時(shí)間,表示取消超時(shí)后的時(shí)間。例:

package main
import (
 "runtime"
 "fmt"
 "time"
 "context"
)
func monitor2(ctx context.Context, index int) {
 for {
  select {
  case v := <- ctx.Done():
   fmt.Printf("monitor2: %v, the received channel value is: %v, ending\n", index, v)
   return
  default:
   fmt.Printf("monitor2: %v in progress...\n", index)
   time.Sleep(2 * time.Second)
  }
 }
}
func monitor1(ctx context.Context, index int) {
 for {
  go monitor2(ctx, index)
  select {
  case v := <- ctx.Done():
   // this branch is only reached when the ch channel is closed, or when data is sent(either true or false)
   fmt.Printf("monitor1: %v, the received channel value is: %v, ending\n", index, v)
   return
  default:
   fmt.Printf("monitor1: %v in progress...\n", index)
   time.Sleep(2 * time.Second)
  }
 }
}
func main() {
 var ctx01 context.Context = nil
 var ctx02 context.Context = nil
 var cancel context.CancelFunc = nil
 ctx01, cancel = context.WithCancel(context.Background())
 ctx02, cancel = context.WithDeadline(ctx01, time.Now().Add(1 * time.Second)) // If it's WithTimeout, just change this line to "ctx02, cancel = context.WithTimeout(ctx01, 1 * time.Second)"
 defer cancel()
 for i := 1; i <= 5; i = i + 1 {
  go monitor1(ctx02, i)
 }
 time.Sleep(5 * time.Second)
 if ctx02.Err() != nil {
  fmt.Println("the cause of cancel is: ", ctx02.Err())
 }
 println(runtime.NumGoroutine())
 println("main program exit!!!!")
}

WithValue

一些必需的元數(shù)據(jù)也可以通過(guò)上下文傳遞,該上下文將附加到上下文中以供使用。元數(shù)據(jù)作為鍵值傳遞,但請(qǐng)注意,鍵必須具有可比性,并且值必須是線程安全的。

package main
import (
 "runtime"
 "fmt"
 "time"
 "context"
)
func monitor(ctx context.Context, index int) {
 for {
  select {
  case <- ctx.Done():
   // this branch is only reached when the ch channel is closed, or when data is sent(either true or false)
   fmt.Printf("monitor %v, end of monitoring. \n", index)
   return
  default:
   var value interface{} = ctx.Value("Nets")
   fmt.Printf("monitor %v, is monitoring %v\n", index, value)
   time.Sleep(2 * time.Second)
  }
 }
}
func main() {
 var ctx01 context.Context = nil
 var ctx02 context.Context = nil
 var cancel context.CancelFunc = nil
 ctx01, cancel = context.WithCancel(context.Background())
 ctx02, cancel = context.WithTimeout(ctx01, 1 * time.Second)
 var ctx03 context.Context = context.WithValue(ctx02, "Nets", "Champion") // key: "Nets", value: "Champion"

 defer cancel()
 for i := 1; i <= 5; i = i + 1 {
  go monitor(ctx03, i)
 }
 time.Sleep(5 * time.Second)
 if ctx02.Err() != nil {
  fmt.Println("the cause of cancel is: ", ctx02.Err())
 }
 println(runtime.NumGoroutine())
 println("main program exit!!!!")
}

關(guān)于上下文,還有一些注意事項(xiàng):不要將Context存儲(chǔ)在結(jié)構(gòu)類型中,而是將Context明確傳遞給需要它的每個(gè)函數(shù),并且Context應(yīng)該是第一個(gè)參數(shù)。

即使函數(shù)允許,也不要傳遞nil Context,或者如果您不確定要使用哪個(gè)Context,請(qǐng)傳遞context。不要將可能作為函數(shù)參數(shù)傳遞給上下文值的變量傳遞。

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

相關(guān)文章

  • GO語(yǔ)言類型查詢類型斷言示例解析

    GO語(yǔ)言類型查詢類型斷言示例解析

    這篇文章主要為大家介紹了GO語(yǔ)言類型判斷及類型斷言,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪
    2022-04-04
  • Go語(yǔ)言panic和recover的用法實(shí)例

    Go語(yǔ)言panic和recover的用法實(shí)例

    panic()和recover()是Go語(yǔ)言中用于處理錯(cuò)誤的兩個(gè)重要函數(shù),本文主要介紹了Go語(yǔ)言panic和recover的用法實(shí)例,panic()用于中止程序并引發(fā)panic,而recover()用于捕獲panic并恢復(fù)程序的執(zhí)行,感興趣的可以了解一下
    2024-01-01
  • GoLang strings.Builder底層實(shí)現(xiàn)方法詳解

    GoLang strings.Builder底層實(shí)現(xiàn)方法詳解

    自從學(xué)習(xí)go一個(gè)月以來(lái),我多少使用了一下strings.Builder,略有心得。你也許知道它,特別是你了解bytes.Buffer的話。所以我在此分享一下我的心得,并希望能對(duì)你有所幫助
    2022-10-10
  • Golang標(biāo)準(zhǔn)庫(kù)binary詳解

    Golang標(biāo)準(zhǔn)庫(kù)binary詳解

    這篇文章主要介紹了Golang標(biāo)準(zhǔn)庫(kù)binary的相關(guān)資料,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-05-05
  • logrus日志自定義格式操作

    logrus日志自定義格式操作

    這篇文章主要介紹了logrus日志自定義格式操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-11-11
  • 創(chuàng)建Go工程化項(xiàng)目布局詳解

    創(chuàng)建Go工程化項(xiàng)目布局詳解

    這篇文章主要介紹了創(chuàng)建Go工程化項(xiàng)目布局詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-09-09
  • Go并發(fā)編程實(shí)踐

    Go并發(fā)編程實(shí)踐

    并發(fā)編程一直是Golang區(qū)別與其他語(yǔ)言的很大優(yōu)勢(shì),也是實(shí)際工作場(chǎng)景中經(jīng)常遇到的。近日筆者在組內(nèi)分享了我們常見(jiàn)的并發(fā)場(chǎng)景,及代碼示例,以期望大家能在遇到相同場(chǎng)景下,能快速的想到解決方案,或者是拿這些方案與自己實(shí)現(xiàn)的比較,取長(zhǎng)補(bǔ)短?,F(xiàn)整理出來(lái)與大家共享
    2017-01-01
  • golang 檢查網(wǎng)絡(luò)狀態(tài)是否正常的方法

    golang 檢查網(wǎng)絡(luò)狀態(tài)是否正常的方法

    今天小編就為大家分享一篇golang 檢查網(wǎng)絡(luò)狀態(tài)是否正常的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2019-07-07
  • Golang拾遺之實(shí)現(xiàn)一個(gè)不可復(fù)制類型詳解

    Golang拾遺之實(shí)現(xiàn)一個(gè)不可復(fù)制類型詳解

    在這篇文章中我們將實(shí)現(xiàn)一個(gè)無(wú)法被復(fù)制的類型,順便加深對(duì)引用類型、值傳遞以及指針的理解。文中的示例代碼講解詳細(xì),感興趣的可以了解一下
    2023-02-02
  • Golang算法問(wèn)題之整數(shù)拆分實(shí)現(xiàn)方法分析

    Golang算法問(wèn)題之整數(shù)拆分實(shí)現(xiàn)方法分析

    這篇文章主要介紹了Golang算法問(wèn)題之整數(shù)拆分實(shí)現(xiàn)方法,結(jié)合實(shí)例形式分析了Go語(yǔ)言數(shù)值運(yùn)算與數(shù)組遍歷相關(guān)操作技巧,需要的朋友可以參考下
    2017-02-02

最新評(píng)論

威信县| 孝感市| 体育| 福州市| 永登县| 曲周县| 信丰县| 澄迈县| 永福县| 德阳市| 阿克陶县| 长泰县| 台南市| 迭部县| 桐梓县| 台山市| 新乡市| 焦作市| 基隆市| 德阳市| 肇州县| 大新县| 民和| 江安县| 双鸭山市| 和政县| 鹤壁市| 马尔康县| 安仁县| 百色市| 芒康县| 霍邱县| 彭水| 神农架林区| 康马县| 万年县| 稻城县| 蓬莱市| 克拉玛依市| 万安县| 永州市|