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

深入了解Golang為什么需要超時(shí)控制

 更新時(shí)間:2023年05月08日 08:22:51   作者:starrySky  
本文將介紹為什么需要超時(shí)控制,然后詳細(xì)介紹Go語言中實(shí)現(xiàn)超時(shí)控制的方法,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起了解一下

1. 簡介

本文將介紹為什么需要超時(shí)控制,然后詳細(xì)介紹Go語言中實(shí)現(xiàn)超時(shí)控制的方法。其中,我們將討論time包和context包實(shí)現(xiàn)超時(shí)控制的具體方式,并說明兩者的適用場(chǎng)景,以便在程序中以更合適的方式來實(shí)現(xiàn)超時(shí)控制,提高程序的穩(wěn)定性和可靠性。

2. 為什么需要超時(shí)控制

超時(shí)控制是指在進(jìn)行網(wǎng)絡(luò)請(qǐng)求或者協(xié)程執(zhí)行等操作時(shí),為了避免程序一直等待,造成資源浪費(fèi),我們需要對(duì)這些操作設(shè)置一個(gè)超時(shí)時(shí)間,在規(guī)定時(shí)間內(nèi)未完成操作,就需要停止等待或者終止操作。

例如,在進(jìn)行網(wǎng)絡(luò)請(qǐng)求時(shí),如果服務(wù)器端出現(xiàn)問題導(dǎo)致沒有及時(shí)響應(yīng),客戶端可能會(huì)一直等待服務(wù)器的響應(yīng),這樣會(huì)造成客戶端資源的浪費(fèi)。

舉個(gè)簡單的例子,比如我們需要從遠(yuǎn)程服務(wù)器獲取某個(gè)資源,我們可以使用以下代碼來進(jìn)行實(shí)現(xiàn):

func getResource() (Resource, error) {
    conn, err := net.Dial("tcp", "example.com:8888")
    if err != nil {
        return nil, err
    }
    defer conn.Close()
    // 發(fā)送請(qǐng)求并等待響應(yīng)
    _, err = conn.Write([]byte("GET /resource HTTP/1.1\r\nHost: example.com\r\n\r\n"))
    if err != nil {
        return nil, err
    }
    resp, err := ioutil.ReadAll(conn)
    if err != nil {
        return nil, err
    }
    // 解析響應(yīng)并返回資源
    return parseResource(resp)
}

但是如果遠(yuǎn)程服務(wù)器在我們發(fā)送請(qǐng)求后一直沒有響應(yīng),那么我們的程序就會(huì)一直等待,無法繼續(xù)執(zhí)行其他任務(wù)。

在某些情況下,這可能會(huì)導(dǎo)致程序的阻塞,從而影響程序的性能和穩(wěn)定性。因此,在進(jìn)行網(wǎng)絡(luò)通信等操作時(shí),尤其是在調(diào)用外部API或者訪問遠(yuǎn)程服務(wù)器時(shí),一定要使用超時(shí)控制。那么,在Go語言中,超時(shí)控制的實(shí)現(xiàn)方式有哪些呢?

3. 超時(shí)控制的方法

 3.1 time包實(shí)現(xiàn)超時(shí)控制    

time包提供了多種方式來實(shí)現(xiàn)超時(shí)控制,包括time.After函數(shù)、time.NewTimer函數(shù)以及time.AfterFunc函數(shù),使用它們可以實(shí)現(xiàn)超時(shí)控制,下面以time.NewTimer函數(shù)為例,說明如何使用其time包實(shí)現(xiàn)超時(shí)控制。代碼示例如下:

// 創(chuàng)建一個(gè)定時(shí)器
timer := time.NewTimer(5 * time.Second)
defer timer.Stop()

// 使用一個(gè)channel來監(jiān)聽任務(wù)是否已完成
ch := make(chan string, 1)     
go func() {         
// 模擬任務(wù)執(zhí)行,休眠5秒         
    time.Sleep(2* time.Second)         
    ch <- "hello world"     
}()

// 通過select語句來等待結(jié)果,任務(wù)正常返回
select {
case <-ch:
    fmt.Println("任務(wù)正常完成")
  // ch 已經(jīng)接收到值,走正常處理邏輯
case <-timer.C:
    fmt.Println("已超時(shí)")
  // 超時(shí),走超時(shí)邏輯
}

在這里例子中,我們使用 time.NewTimer 方法創(chuàng)建一個(gè)定時(shí)器,超時(shí)時(shí)間為2秒鐘。然后在 select 語句中使用來等待結(jié)果,哪個(gè)先返回就使用哪個(gè)。

如果操作在2秒鐘內(nèi)完成,那么任務(wù)正常完成;如果操作超過2秒鐘仍未完成,此時(shí)select語句中<-timer.C將接收到值,走超時(shí)處理邏輯。

3.2 context實(shí)現(xiàn)超時(shí)控制

Context 接口是 Go 語言標(biāo)準(zhǔn)庫中提供的一個(gè)上下文(Context)管理機(jī)制。它允許在程序的不同部分之間傳遞上下文信息,并且可以通過它實(shí)現(xiàn)超時(shí)控制、取消操作以及截?cái)嗖僮鞯裙δ?。其中?code>Context接口存在一個(gè)timerCtx的實(shí)現(xiàn),其可以設(shè)定一個(gè)超時(shí)時(shí)間,在到達(dá)超時(shí)時(shí)間后,timerCtx對(duì)象的 done channel 將會(huì)被關(guān)閉。

當(dāng)需要判斷是否超時(shí)時(shí),只需要調(diào)用 context 對(duì)象的 Done 方法,其會(huì)返回timerCtx對(duì)象中的done channel,如果有數(shù)據(jù)返回,則說明已經(jīng)超時(shí)?;诖?,我們便可以實(shí)現(xiàn)超時(shí)控制。代碼示例如下:

// 創(chuàng)建一個(gè)timerCtx,設(shè)置超時(shí)時(shí)間為3秒     
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)     
// 調(diào)用cancel函數(shù),釋放占用的資源  
defer cancel()
// 使用一個(gè)channel來監(jiān)聽任務(wù)是否已完成
ch := make(chan string, 1)     
go func() {         
// 模擬任務(wù)執(zhí)行,休眠5秒         
    time.Sleep(2* time.Second)         
    ch <- "hello world"     
}()
// 通過select語句來等待結(jié)果,任務(wù)正常返回
select {
    case <-ctx.Done():
        fmt.Println("timeout")
    case result := <-ch:
        fmt.Println(result)
}

這里通過context.WithTimeout創(chuàng)建一個(gè)timerCtx,設(shè)定好超時(shí)時(shí)間,超時(shí)時(shí)間為3s。然后啟動(dòng)一個(gè)協(xié)程來執(zhí)行具體的業(yè)務(wù)邏輯。

之后通過select語句,對(duì)timerCtx和業(yè)務(wù)執(zhí)行結(jié)果同時(shí)進(jìn)行監(jiān)聽,當(dāng)任務(wù)處理超時(shí)時(shí),則執(zhí)行超時(shí)邏輯;如果任務(wù)在超時(shí)前完成,則執(zhí)行正常處理流程。通過這種方式,實(shí)現(xiàn)了請(qǐng)求的超時(shí)處理。

4. 適用場(chǎng)景分析

從上文可以看出,timetimerCtx都可以用于實(shí)現(xiàn)超時(shí)控制,但是事實(shí)上兩者的適用場(chǎng)景其實(shí)是不太相同的。在某些場(chǎng)景下,超時(shí)控制并不適合使用time來實(shí)現(xiàn),而是使用timerCtx來實(shí)現(xiàn)更為合適。而在某些場(chǎng)景下,其實(shí)兩種實(shí)現(xiàn)方式均可。

下面我簡單介紹幾種常見的場(chǎng)景,然后對(duì)其來進(jìn)行分析,從而能夠在合適的場(chǎng)景下使用恰當(dāng)?shù)脤?shí)現(xiàn)。

4.1 簡單超時(shí)控制

舉個(gè)例子,假設(shè)我們需要從一個(gè)遠(yuǎn)程服務(wù)獲取一些數(shù)據(jù),我們可以使用Go標(biāo)準(zhǔn)庫中的http包進(jìn)行網(wǎng)絡(luò)請(qǐng)求,大概請(qǐng)求函數(shù)如下:

func makeRequest(url string) (string, error) {
   // 請(qǐng)求數(shù)據(jù)
}

此時(shí)為了避免請(qǐng)求響應(yīng)時(shí)間過長,導(dǎo)致程序長時(shí)間處于等待狀態(tài),此時(shí)我們需要對(duì)這個(gè)函數(shù)實(shí)現(xiàn)超時(shí)處理,確保程序能夠及時(shí)響應(yīng)其他請(qǐng)求,而不是一直等待。

為了實(shí)現(xiàn)這個(gè)目的,此時(shí)可以使用time包或者timerCtx來實(shí)現(xiàn)超時(shí)控制。在makeRequest函數(shù)中實(shí)現(xiàn)超時(shí)控制,這里代碼展示與第三點(diǎn)超時(shí)控制的方法中的代碼示例大體相同,只需要將協(xié)程中sleep函數(shù)切換成具體的業(yè)務(wù)邏輯即可,這里不再贅述。而且,查看上面代碼示例,我們也可以看出來timer或者timerCtx在這個(gè)場(chǎng)景下,區(qū)別并不大,此時(shí)是可以相互替換的。

因此,對(duì)于這種控制某個(gè)函數(shù)的執(zhí)行時(shí)間的場(chǎng)景,是可以任意挑選time或者timerCtx其中一個(gè)來實(shí)現(xiàn)的。

4.2 可選超時(shí)控制

這里我們實(shí)現(xiàn)一個(gè)方法,用于建立網(wǎng)絡(luò)連接,用戶調(diào)用該方法時(shí),傳入待建立連接的地址列表,然后該方法通過遍歷傳入的地址列表,并針對(duì)每一個(gè)地址進(jìn)行連接嘗試,直到連接成功或者所有地址都嘗試完成。函數(shù)定義如下:

func dialSerial(ras addrList) (Conn, error){
   // 執(zhí)行建立網(wǎng)絡(luò)連接的邏輯
}

基于此,在這個(gè)函數(shù)的基礎(chǔ)上,實(shí)現(xiàn)一個(gè)可選的超時(shí)控制的功能。如果用戶調(diào)用該方法時(shí),有指定超時(shí)時(shí)間的話,此時(shí)便進(jìn)行超時(shí)控制;如果未指定超時(shí)時(shí)間的話,此時(shí)便無需執(zhí)行超時(shí)控制。這里分別使用time包以及context實(shí)現(xiàn)。

首先對(duì)于time包實(shí)現(xiàn)可選的超時(shí)控制,可以通過函數(shù)參數(shù)傳遞定時(shí)器來實(shí)現(xiàn)可選的超時(shí)控制。具體地說,可以將定時(shí)器作為一個(gè)time.Timer類型的參數(shù)傳遞給函數(shù),然后在函數(shù)中使用select監(jiān)聽time.Timer是超時(shí);如果沒有傳遞定時(shí)器實(shí)例,則默認(rèn)不進(jìn)行超時(shí)控制,代碼實(shí)現(xiàn)如下所示:

func dialSerial(timeout time.Timer, ras addrList) (Conn, error){
   // 執(zhí)行建立網(wǎng)絡(luò)連接的邏輯,對(duì)每個(gè)地址嘗試建立連接時(shí),先檢查是否超時(shí)
   for i, ra := range ras {
          // 通過這里來進(jìn)行超時(shí)控制,首先先判斷是否傳入定時(shí)器實(shí)例
          if timeout != nil {
              select {
              // 監(jiān)聽是否超時(shí)
              case <-timeout.C:
                  return nil, errors.New("timeout")
              default:
              }
          }
         // 執(zhí)行后續(xù)建立網(wǎng)絡(luò)連接的邏輯          
   }
}

接著則是使用timerCtx來實(shí)現(xiàn)超時(shí)控制的實(shí)現(xiàn),可以通過函數(shù)傳遞一個(gè)context.Context接口的參數(shù)來實(shí)現(xiàn)超時(shí)控制。

具體來說,用戶可以傳遞一個(gè)context.Context接口的實(shí)現(xiàn),如果有指定超時(shí)時(shí)間,則傳入一個(gè)timerCtx的實(shí)現(xiàn);如果無需超時(shí)控制,此時(shí)可以傳入context.Background,其永遠(yuǎn)不會(huì)超時(shí)。然后函數(shù)中通過調(diào)用Done方法來判斷是否超時(shí),從而實(shí)現(xiàn)超時(shí)控制。代碼實(shí)現(xiàn)如下:

func dialSerial(ctx context.Context, ras addrList) (Conn, error){
   // 執(zhí)行建立網(wǎng)絡(luò)連接的邏輯,對(duì)每個(gè)地址嘗試建立連接時(shí),先檢查是否超時(shí)
   for i, ra := range ras {
       select {
       case <-ctx.Done():
          return nil, &OpError{Op: "dial", Net: sd.network, Source: sd.LocalAddr, Addr: ra, Err: mapErr(ctx.Err())}
       default: 
       }
       // 執(zhí)行建立網(wǎng)絡(luò)連接的邏輯
   }
}

查看上述代碼中,dialSerial函數(shù)實(shí)現(xiàn)可選超時(shí)控制,看起來只是傳入?yún)?shù)不同,一個(gè)是傳入定時(shí)器time.Timer實(shí)例,一個(gè)是傳入context.Context接口實(shí)例而已,但是實(shí)際上不僅僅如此。

首先是代碼的可讀性上來看,傳入time.Timer實(shí)例來實(shí)現(xiàn)超時(shí)控制,并非Go中常見的實(shí)現(xiàn)方式,用戶不好理解;而對(duì)于context.Context接口來說,其被廣泛使用,如果要實(shí)現(xiàn)超時(shí)控制,用戶只需要傳入一個(gè)timerCtx實(shí)例即可,用戶使用起來沒有額外的心智負(fù)擔(dān),代碼可讀性更強(qiáng)。

其次是對(duì)于整個(gè)Go語言的生態(tài)來說,context.Context接口在Go語言標(biāo)準(zhǔn)庫中得到廣泛使用,而且普遍超時(shí)控制都是使用timerCtx來實(shí)現(xiàn)的,如果此時(shí)傳入一個(gè)time.Timer實(shí)例,實(shí)際上是與整個(gè)Go語言的超時(shí)控制的格格不入的。以上面dialSerial方法為例,其建立網(wǎng)絡(luò)連接是需要調(diào)用底層函數(shù)來協(xié)助實(shí)現(xiàn)的,如:

func (fd *netFD) connect(ctx context.Context, la, ra syscall.Sockaddr) (rsa syscall.Sockaddr, ret error) {
    // 執(zhí)行建立連接的邏輯
    switch err := connectFunc(fd.pfd.Sysfd, ra); err {
    // 未報(bào)錯(cuò),此時(shí)檢查是否超時(shí)
    case nil, syscall.EISCONN:
       select {
       case <-ctx.Done():
           // 如果已經(jīng)超時(shí),此時(shí)返回超時(shí)錯(cuò)誤
          return nil, mapErr(ctx.Err())
       default:
       }
     }
}

而且剛好,該函數(shù)也是實(shí)現(xiàn)了可選的超時(shí)控制,而且是通過timerCtx來實(shí)現(xiàn)的,如果此時(shí)傳入的timerCtx已經(jīng)超時(shí),此時(shí)函數(shù)會(huì)直接返回一個(gè)超時(shí)錯(cuò)誤。

如果上面dialSerial的超時(shí)控制是通過context.Context的接口實(shí)例來實(shí)現(xiàn)的話,此時(shí)調(diào)用函數(shù)時(shí),直接將外部的Context實(shí)例作為參數(shù)傳入connect函數(shù),外層調(diào)用也無需再檢查函數(shù)是否超時(shí),代碼的可復(fù)用性更高。

相對(duì)的,如果dialSerial的超時(shí)控制是通過傳入定時(shí)器實(shí)現(xiàn)的,此時(shí)便無法很好利用connect方法已經(jīng)實(shí)現(xiàn)的超時(shí)檢查的機(jī)制。

因此,綜上所述,使用 context.Context 接口作為可選的超時(shí)控制參數(shù),相比于使用 time.Timer,更加適合同時(shí)也更加高效,與整個(gè)Go語言的實(shí)現(xiàn)也能夠更好得進(jìn)行融合在一起。

總結(jié)

ContextTime 都是 Go 語言中實(shí)現(xiàn)超時(shí)控制的方法,它們各有優(yōu)缺點(diǎn),不能說哪一種實(shí)現(xiàn)更好,要根據(jù)具體的場(chǎng)景來選擇使用哪種方法。

在一些簡單的場(chǎng)景下,使用 Time 包實(shí)現(xiàn)超時(shí)控制可能更加方便,因?yàn)樗?API 更加簡單,只需要使用 time.After() 函數(shù)即可實(shí)現(xiàn)超時(shí)控制。

但是,如果涉及到在多個(gè)函數(shù),或者是需要多個(gè)goroutine之間傳遞的話,此時(shí)使用Context來實(shí)現(xiàn)超時(shí)控制可能更加適合。

5.總結(jié)

本文介紹了需要超時(shí)控制的原因,主要是避免無限期等待,防止資源泄漏和提高程序響應(yīng)速度這幾點(diǎn)內(nèi)容。

接著我們介紹了Go語言中實(shí)現(xiàn)超時(shí)控制的方法,包括使用time實(shí)現(xiàn)超時(shí)控制以及使用context實(shí)現(xiàn)超時(shí)控制,并給出了簡單的代碼示例。

在接下來,我們便這兩種實(shí)現(xiàn)的適用場(chǎng)景進(jìn)行分析,明確了在哪些場(chǎng)景下,適合使用time實(shí)現(xiàn)超時(shí)控制,以及在哪些場(chǎng)景下,使用timerCtx來實(shí)現(xiàn)更為高效。

基于此,完成了為什么需要超時(shí)控制的介紹,希望能夠讓大家在遇到需要超時(shí)控制的場(chǎng)景下,更好得去進(jìn)行實(shí)現(xiàn)。

以上就是深入了解Golang為什么需要超時(shí)控制的詳細(xì)內(nèi)容,更多關(guān)于Golang超時(shí)控制的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Golang 實(shí)現(xiàn)超大文件讀取的兩種方法

    Golang 實(shí)現(xiàn)超大文件讀取的兩種方法

    這篇文章主要介紹了Golang 實(shí)現(xiàn)超大文件讀取的兩種方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-04-04
  • 用Go+WebSocket快速實(shí)現(xiàn)一個(gè)chat服務(wù)

    用Go+WebSocket快速實(shí)現(xiàn)一個(gè)chat服務(wù)

    這篇文章主要介紹了用Go+WebSocket快速實(shí)現(xiàn)一個(gè)chat服務(wù),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • Go使用XORM操作MySQL的陷阱盤點(diǎn)分析

    Go使用XORM操作MySQL的陷阱盤點(diǎn)分析

    在?Go?語言開發(fā)中,大家為了方便,通常會(huì)選擇使用?ORM?操作數(shù)據(jù)庫,比如使用?XORM?或?GORM?操作?MySQL,本文我們來介紹一下使用?XORM[3]?操作?MySQL?可能會(huì)遇到的陷阱
    2023-11-11
  • golang 接口嵌套實(shí)現(xiàn)復(fù)用的操作

    golang 接口嵌套實(shí)現(xiàn)復(fù)用的操作

    這篇文章主要介紹了golang 接口嵌套實(shí)現(xiàn)復(fù)用的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-04-04
  • Go語言數(shù)據(jù)結(jié)構(gòu)之希爾排序示例詳解

    Go語言數(shù)據(jù)結(jié)構(gòu)之希爾排序示例詳解

    這篇文章主要為大家介紹了Go語言數(shù)據(jù)結(jié)構(gòu)之希爾排序示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • Golang解析JSON遇到的坑及解決方法

    Golang解析JSON遇到的坑及解決方法

    這篇文章主要為大家介紹了Golang解析JSON時(shí)會(huì)遇到的一些坑及解決方法,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)Go語言有一點(diǎn)的幫助,需要的可以參考一下
    2023-02-02
  • 使用Golang輕松實(shí)現(xiàn)JWT身份驗(yàn)證的示例代碼

    使用Golang輕松實(shí)現(xiàn)JWT身份驗(yàn)證的示例代碼

    JSON Web Tokens (JWT)是一種流行的安全方法,用于在兩個(gè)方之間表示聲明,本文主要為大家詳細(xì)介紹了實(shí)現(xiàn)Go應(yīng)用程序中的JWT身份驗(yàn)證過程,需要的可以參考下
    2024-02-02
  • Go語言colly框架的快速入門

    Go語言colly框架的快速入門

    Python?中非常知名的爬蟲框架有Scrapy,Go?中也有一些?star?數(shù)較高的爬蟲框架,colly就是其中的佼佼者,它?API?簡潔,性能優(yōu)良,開箱即用,今天就來快速學(xué)習(xí)一下吧
    2023-07-07
  • Golang交叉編譯之跨平臺(tái)編譯使用詳解

    Golang交叉編譯之跨平臺(tái)編譯使用詳解

    這篇文章主要為大家介紹了Golang交叉編譯之跨平臺(tái)編譯使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-10-10
  • 詳解Golang中零拷貝的原理以及實(shí)踐

    詳解Golang中零拷貝的原理以及實(shí)踐

    零拷貝技術(shù)相信大家都有所耳聞,但是本文不僅會(huì)講述零拷貝技術(shù)的原理,并將從實(shí)際代碼出發(fā),看看零拷貝技術(shù)在golang中的應(yīng)用,現(xiàn)在讓我們開始吧
    2023-07-07

最新評(píng)論