中文字幕理论片,69视频免费在线观看,亚洲成人app,国产1级毛片,刘涛最大尺度戏视频,欧美亚洲美女视频,2021韩国美女仙女屋vip视频

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費(fèi)電子書(shū)等14項(xiàng)超值服

開(kāi)通VIP
回答我,停止 Goroutine 有幾種方法?

大家好,我是煎魚(yú)。

協(xié)程(goroutine)作為 Go 語(yǔ)言的扛把子,經(jīng)常在各種 Go 工程項(xiàng)目中頻繁露面,甚至有人會(huì)為了用 goroutine 而強(qiáng)行用他。

在 Go 工程師的面試中,也繞不開(kāi)他,會(huì)有人問(wèn) ”如何停止一個(gè) goroutine?”,一下子就把話題范圍擴(kuò)大了,這是一個(gè)涉及多個(gè)知識(shí)點(diǎn)的話題,能進(jìn)一步深入問(wèn)。

為此,今天煎魚(yú)就帶大家了解一下停止 goroutine 的方法!

goroutine 案例

在日常的工作中,我們常會(huì)有這樣的 Go 代碼,go 關(guān)鍵字一把搜起一個(gè) goroutine:

func main() { 
 ch := make(chan string6)
 go func() {
  for {
   ch <- '腦子進(jìn)煎魚(yú)了'
  }
 }()
}

初入 goroutine 大門(mén)的開(kāi)發(fā)者可能就完事了,但跑一段時(shí)間后,他就可能會(huì)遇到一些問(wèn)題,苦苦排查...

像是:當(dāng) goroutine 內(nèi)的任務(wù),運(yùn)行的太久,又或是卡死了...就會(huì)一直阻塞在系統(tǒng)中,變成 goroutine 泄露,或是間接造成資源暴漲,會(huì)帶來(lái)許多的問(wèn)題。

如何在停止 goroutine,就成了一門(mén)必修技能了,不懂就沒(méi)法用好 goroutine。

關(guān)閉 channel

第一種方法,就是借助 channel 的 close 機(jī)制來(lái)完成對(duì) goroutine 的精確控制。

代碼如下:

func main() {
 ch := make(chan string6)
 go func() {
  for {
   v, ok := <-ch
   if !ok {
    fmt.Println('結(jié)束')
    return
   }
   fmt.Println(v)
  }
 }()

 ch <- '煎魚(yú)還沒(méi)進(jìn)鍋里...'
 ch <- '煎魚(yú)進(jìn)腦子里了!'
 close(ch)
 time.Sleep(time.Second)
}

在 Go 語(yǔ)言的 channel 中,channel 接受數(shù)據(jù)有兩種方法:

msg := <-ch
msg, ok := <-ch

這兩種方式對(duì)應(yīng)著不同的 runtime 方法,我們可以利用其第二個(gè)參數(shù)進(jìn)行判別,當(dāng)關(guān)閉 channel 時(shí),就根據(jù)其返回結(jié)果跳出。

另外我們也可以利用 for range 的特性:

 go func() {
  for {
   for v := range ch {
    fmt.Println(v)
   }
  }
 }()

其會(huì)一直循環(huán)遍歷通道 ch,直到其關(guān)閉為止,是頗為常見(jiàn)的一種用法。

定期輪詢 channel

第二種方法,是更為精細(xì)的方法,其結(jié)合了第一種方法和類(lèi)似信號(hào)量的處理方式。

代碼如下:

func main() {
 ch := make(chan string6)
 done := make(chan struct{})
 go func() {
  for {
   select {
   case ch <- '腦子進(jìn)煎魚(yú)了':
   case <-done:
    close(ch)
    return
   }
   time.Sleep(100 * time.Millisecond)
  }
 }()

 go func() {
  time.Sleep(3 * time.Second)
  done <- struct{}{}
 }()

 for i := range ch {
  fmt.Println('接收到的值: ', i)
 }

 fmt.Println('結(jié)束')
}

在上述代碼中,我們聲明了變量 done,其類(lèi)型為 channel,用于作為信號(hào)量處理 goroutine 的關(guān)閉。

而 goroutine 的關(guān)閉是不知道什么時(shí)候發(fā)生的,因此在 Go 語(yǔ)言中會(huì)利用 for-loop 結(jié)合 select 關(guān)鍵字進(jìn)行監(jiān)聽(tīng),再進(jìn)行完畢相關(guān)的業(yè)務(wù)處理后,再調(diào)用 close 方法正式關(guān)閉 channel。

若程序邏輯比較簡(jiǎn)單結(jié)構(gòu)化,也可以不調(diào)用 close 方法,因?yàn)?goroutine 會(huì)自然結(jié)束,也就不需要手動(dòng)關(guān)閉了。

使用 context

第三種方法,可以借助 Go 語(yǔ)言的上下文(context)來(lái)做 goroutine 的控制和關(guān)閉。

代碼如下:

func main() {
 ch := make(chan struct{})
 ctx, cancel := context.WithCancel(context.Background())

 go func(ctx context.Context) {
  for {
   select {
   case <-ctx.Done():
    ch <- struct{}{}
    return
   default:
    fmt.Println('煎魚(yú)還沒(méi)到鍋里...')
   }

   time.Sleep(500 * time.Millisecond)
  }
 }(ctx)

 go func() {
  time.Sleep(3 * time.Second)
  cancel()
 }()

 <-ch
 fmt.Println('結(jié)束')
}

在 context 中,我們可以借助 ctx.Done 獲取一個(gè)只讀的 channel,類(lèi)型為結(jié)構(gòu)體??捎糜谧R(shí)別當(dāng)前 channel 是否已經(jīng)被關(guān)閉,其原因可能是到期,也可能是被取消了。

因此 context 對(duì)于跨 goroutine 控制有自己的靈活之處,可以調(diào)用 context.WithTimeout 來(lái)根據(jù)時(shí)間控制,也可以自己主動(dòng)地調(diào)用 cancel 方法來(lái)手動(dòng)關(guān)閉。

干掉另外一個(gè) goroutine

在了解了停止 goroutine 的 3 種經(jīng)典方法后,又有小伙伴提出了新的想法。就是 “我想在 goroutineA 里去停止 goroutineB,有辦法嗎?

答案是不能,因?yàn)樵?Go 語(yǔ)言中,goroutine 只能自己主動(dòng)退出,一般通過(guò) channel 來(lái)控制,不能被外界的其他 goroutine 關(guān)閉或干掉,也沒(méi)有 goroutine 句柄的顯式概念。

go/issues/32610

在 Go issues 中也有人提過(guò)類(lèi)似問(wèn)題,Dave Cheney 給出了一些思考:

  • 如果一個(gè) goroutine 被強(qiáng)行停止了,它所擁有的資源會(huì)發(fā)生什么?堆棧被解開(kāi)了嗎?defer 是否被執(zhí)行?
    • 如果執(zhí)行 defer,該 goroutine 可能可以繼續(xù)無(wú)限期地生存下去。
    • 如果不執(zhí)行 defer,該 goroutine 原本的應(yīng)用程序系統(tǒng)設(shè)計(jì)邏輯將會(huì)被破壞,這肯定不合理。
  • 如果允許強(qiáng)制停止 goroutine,是要釋放所有東西,還是直接把它從調(diào)度器中踢出去,你想通過(guò)此解決什么問(wèn)題?

這都是值得深思的,另外一旦放開(kāi)這種限制。作為程序員,你維護(hù)代碼。很有可能就不知道 goroutine 的句柄被傳到了哪里,又是在何時(shí)何地被人莫名其妙關(guān)閉,非常糟糕...

總結(jié)

在今天這篇文章中,我們介紹了在 Go 語(yǔ)言中停止 goroutine 的三大經(jīng)典方法(channel、context,channel+context)和其背后的使用原理。

同時(shí)針對(duì) goroutine 不可以跨 goroutine 強(qiáng)制停止的原因進(jìn)行了分析。其實(shí) goroutine 的設(shè)計(jì)就是這樣的,包括像 goroutine+panic+recover 的設(shè)計(jì)也是遵循這個(gè)原理,因此也有的 Go 開(kāi)發(fā)者總是會(huì)誤以為跨 goroutine 能有 recover 接住...

記住,在 Go 語(yǔ)言中每一個(gè) goroutine 都需要自己承擔(dān)自己的任何責(zé)任,這是基本原則。

(你已經(jīng)是個(gè)成熟的 goroutine 了...)

腦子進(jìn)煎魚(yú)了
分享計(jì)算機(jī)基礎(chǔ)、Go 語(yǔ)言、微服務(wù)架構(gòu)和系統(tǒng)設(shè)計(jì);著有圖書(shū)《Go 語(yǔ)言編程之旅》。
127篇原創(chuàng)內(nèi)容
公眾號(hào)

關(guān)注煎魚(yú),吸取他的知識(shí) ??


你好,我是煎魚(yú)。高一折騰過(guò)前端,參加過(guò)國(guó)賽拿了獎(jiǎng),大學(xué)搞過(guò) PHP?,F(xiàn)在整 Go,在公司負(fù)責(zé)微服務(wù)架構(gòu)等相關(guān)工作推進(jìn)和研發(fā)。

從大學(xué)開(kāi)始靠自己賺生活費(fèi)和學(xué)費(fèi),到出版 Go 暢銷(xiāo)書(shū)《Go 語(yǔ)言編程之旅》,再到獲得 GOP(Go 領(lǐng)域最有觀點(diǎn)專(zhuān)家)榮譽(yù),點(diǎn)擊藍(lán)字查看我的出書(shū)之路。

日常分享高質(zhì)量文章,輸出 Go 面試、工作經(jīng)驗(yàn)、架構(gòu)設(shè)計(jì),加微信拉讀者交流群,記得點(diǎn)贊!

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
Go語(yǔ)言實(shí)戰(zhàn)筆記(二十)| Go Context | 飛雪無(wú)情的博客
?超強(qiáng)指南!Golang 并發(fā)編程
高性能 Go 的 6 個(gè)技巧 — Go 高級(jí)主題
Go 語(yǔ)言簡(jiǎn)介(下)— 特性
go語(yǔ)言WaitGroup用法 | 熊窩窩
Go 語(yǔ)言系列30:異常處理
更多類(lèi)似文章 >>
生活服務(wù)
熱點(diǎn)新聞
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服