佳木斯湛栽影视文化发展公司

主頁 > 知識庫 > Golang實現(xiàn)超時退出的三種方式

Golang實現(xiàn)超時退出的三種方式

熱門標(biāo)簽:地方門戶網(wǎng)站 AI電銷 Linux服務(wù)器 鐵路電話系統(tǒng) 網(wǎng)站排名優(yōu)化 服務(wù)外包 呼叫中心市場需求 百度競價排名

前段時間發(fā)現(xiàn)線上有個服務(wù)接口,總是間歇性告警,有時候一天兩三次,有時候一天都沒有。

告警的邏輯是在一個接口中異步調(diào)用了另一個HTTP接口,這個HTTP接口調(diào)用出現(xiàn)超時。但是我去問了負(fù)責(zé)這個HTTP接口的同學(xué),人家說他們的接口相應(yīng)都是毫秒級別,還截圖監(jiān)控了,有圖有真相,我還能說啥。

但是,超時是確實存在的,只是請求還可能沒有到人家服務(wù)那邊。

這種偶發(fā)性問題不好復(fù)現(xiàn),偶爾來個告警也挺煩的,第一反應(yīng)還是先解決問題,思路也簡單,失敗后重試。

解決方法

且不談重試策略,先說說什么時候觸發(fā)重試。

我們可以在接口請求出錯拋出err的時候重試,但是這種不好控制,如果一個請求出去,十來秒都沒有響應(yīng),則這個協(xié)程就要傻傻的等他報錯才能重試,浪費生命啊~

所以結(jié)合上面同學(xué)給出的毫秒級響應(yīng)指標(biāo),可以設(shè)定一個超時時間,如果在指定超時時間后沒有返回結(jié)果,則重試(這篇重試不是重點)。

func AsyncCall() {
 ctx, cancel := context.WithTimeout(context.Background(), time.Duration(time.Millisecond*800))
 defer cancel()
 go func(ctx context.Context) {
 // 發(fā)送HTTP請求
 }()

 select {
 case -ctx.Done():
 fmt.Println("call successfully!!!")
 return
 case -time.After(time.Duration(time.Millisecond * 900)):
 fmt.Println("timeout!!!")
 return
 }
}

說明

1、通過context的WithTimeout設(shè)置一個有效時間為800毫秒的context。

2、該context會在耗盡800毫秒后或者方法執(zhí)行完成后結(jié)束,結(jié)束的時候會向通道ctx.Done發(fā)送信號。

3、有人可能要問,你這里已經(jīng)設(shè)置了context的有效時間,為什么還要加上這個time.After呢?

這是因為該方法內(nèi)的context是自己申明的,可以手動設(shè)置對應(yīng)的超時時間,但是在大多數(shù)場景,這里的ctx是從上游一直傳遞過來的,對于上游傳遞過來的context還剩多少時間,我們是不知道的,所以這時候通過time.After設(shè)置一個自己預(yù)期的超時時間就很有必要了。

4、注意,這里要記得調(diào)用cancel(),不然即使提前執(zhí)行完了,還要傻傻等到800毫秒后context才會被釋放。

總結(jié)

上面的超時控制是搭配使用了ctx.Done和time.After。

Done通道負(fù)責(zé)監(jiān)聽context啥時候完事,如果在time.After設(shè)置的超時時間到了,你還沒完事,那我就不等了,執(zhí)行超時后的邏輯代碼。

舉一反三

那么,除了上面這種超時控制策略,還有其他的套路嗎?

有,但是大同小異。

第一種:使用time.NewTimer

func AsyncCall() {
 ctx, cancel := context.WithTimeout(context.Background(), time.Duration(time.Millisecond * 800))
 defer cancel()
 timer := time.NewTimer(time.Duration(time.Millisecond * 900))

 go func(ctx context.Context) {
 // 發(fā)送HTTP請求
 }()

 select {
 case -ctx.Done():
 timer.Stop()
 timer.Reset(time.Second)
 fmt.Println("call successfully!!!")
 return
 case -timer.C:
 fmt.Println("timeout!!!")
 return
 }
}

這里的主要區(qū)別是將time.After換成了time.NewTimer,也是同樣的思路如果接口調(diào)用提前完成,則監(jiān)聽到Done信號,然后關(guān)閉定時器。

否則的話,會在指定的timer即900毫秒后執(zhí)行超時后的業(yè)務(wù)邏輯。

第二種:使用通道

func AsyncCall() {
 ctx := context.Background()
 done := make(chan struct{}, 1)

 go func(ctx context.Context) {
 // 發(fā)送HTTP請求
 done - struct{}{}
 }()

 select {
 case -done:
 fmt.Println("call successfully!!!")
 return
 case -time.After(time.Duration(800 * time.Millisecond)):
 fmt.Println("timeout!!!")
 return
 }
}

1、這里主要利用通道可以在協(xié)程之間通信的特點,當(dāng)調(diào)用成功后,向done通道發(fā)送信號。

2、監(jiān)聽Done信號,如果在time.After超時時間之前接收到,則正常返回,否則走向time.After的超時邏輯,執(zhí)行超時邏輯代碼。

3、這里使用的是通道和time.After組合,也可以使用通道和time.NewTimer組合。

總結(jié)

本篇主要介紹如何實現(xiàn)超時控制,主要有三種

1、context.WithTimeout/context.WithDeadline + time.After

2、context.WithTimeout/context.WithDeadline + time.NewTimer

3、channel + time.After/time.NewTimer

到此這篇關(guān)于Golang三種方式實現(xiàn)超時退出的文章就介紹到這了,更多相關(guān)Golang超時退出內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

您可能感興趣的文章:
  • Go語言 go程釋放操作(退出/銷毀)
  • golang 阻止主goroutine退出的操作
  • Golang信號處理及如何實現(xiàn)進(jìn)程的優(yōu)雅退出詳解
  • Golang實現(xiàn)for循環(huán)運行超時后自動退出的方法
  • 解決go在函數(shù)退出后子協(xié)程的退出問題

標(biāo)簽:湖南 仙桃 黃山 崇左 蘭州 衡水 湘潭 銅川

巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《Golang實現(xiàn)超時退出的三種方式》,本文關(guān)鍵詞  ;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問題,煩請?zhí)峁┫嚓P(guān)信息告之我們,我們將及時溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無關(guān)。
  • 相關(guān)文章
  • 收縮
    • 微信客服
    • 微信二維碼
    • 電話咨詢

    • 400-1100-266
    普格县| 江永县| 乌什县| 化州市| 孟村| 米易县| 乾安县| 太原市| 子长县| 连江县| 历史| 西峡县| 通化市| 鹤庆县| 诸暨市| 和田市| 岳池县| 彰武县| 咸宁市| 杭锦后旗| 花垣县| 博白县| 巨野县| 米易县| 鸡泽县| 财经| 城固县| 那坡县| 红安县| 临泉县| 阿拉善右旗| 义马市| 武夷山市| 沁水县| 澄江县| 茌平县| 台南县| 茶陵县| 称多县| 南投县| 寿阳县|