上下文超時和取消

2021-10-25 08:14:32 字數 2711 閱讀 2946

go 有乙個包名為`context`[8]專門處理類似的場景。

context 包在 go 1.7 版本中提公升為標準庫,在之前的版本中,以`golang.org/x/net/context`[9]的路徑作為go sub-repository packages[10]出現。

net/http 包中的的 request 型別已經有 context 與之繫結。從 go 1.7 開始,request 新增了乙個返回請求的上下文的`context` 方法[12]。對於進來的請求,在客戶端關閉連線、請求被取消(http/2 中)或 servehttp 方法返回後,服務端會取消上下文。

我們期望的現象是,當客戶端取消請求(輸入了 ctrl + c)或一段時間後timeouthandler 繼續執行然後終止請求時,服務端會停止後續的處理。進而關閉所有的連線,釋放所有被執行中的處理程序(及它的所有子協程)占用的資源。

我們把 context 作為引數傳給 slowapicall 函式:

func slowapicall(ctx context.context) string 

}func slowhandler(w http.responsewriter, r *http.request)

在例子中我們利用了請求上下文,實際中怎麼用呢?`context` 型別[13]有個 done 屬性,型別為 <-chan struct{}。當程序處理完成時,done 關閉,此時表示上下文應該被取消,而這正是例子中我們需要的。

我們在 slowapicall 函式中用 select 處理 ctx.done 通道。當我們通過 done 通道接收乙個空的 struct 時,意味著上下文取消,我們需要讓 slowapicall 函式返回乙個空字串。

func slowapicall(ctx context.context) string 

}

(這就是使用 select 而不是 time.sleep -- 這裡我們只能用 select 處理 done 通道。)

在這個簡單的例子中,我們成功得到了結果 -- 當我們從 done 通道接收值時,我們列印了一行日誌到 stdout 並返回了乙個空字串。在更複雜的情況下,如傳送真實的 api 請求,你可能需要關閉連線或清理檔案描述符。

我們再啟動服務,傳送乙個 crul 請求:

# the curl command:

$ curl localhost:8888

timeout!

# the server output:

$ go run server.go

2019/12/30 00:07:15 slowapicall was supposed to take 2 seconds, but was canceled.

檢查輸出:我們傳送了 crul 請求到服務,它耗時超過 1 秒,服務取消了 slowapicall 函式。我們幾乎不需要寫任何**。timeouthandler 為我們代勞了 -- 當處理耗時超過預期時,timeouthandler 終止了處理程序並取消請求上下文。

timeouthandler 是在`timeouthandler.servehttp` 方法[14]中取消上下文的:

}上面例子中,我們通過呼叫 context.withtimeout 來使用請求上下文。超時值 h.dt (timeouthandler 的第二個引數)設定給了上下文。返回的上下文是請求上下文設定了超時值後的乙份拷貝。隨後,它作為請求上下文傳給r.withcontext(ctx)。

context.withtimeout 方法執行了上下文取消。它返回了 context 設定了乙個超時值之後的副本。當到達超時時間後,就取消上下文。

這裡是執行的**:

// taken from: 

func withtimeout(parent context, timeout time.duration) (context, cancelfunc) 

// taken from: 

func withdeadline(parent context, d time.time) (context, cancelfunc) 

// *snipped*

if c.err == nil )

}return c, func() 

}

這裡我們又看到了截止時間。withdeadline 函式設定了乙個 d 到達之後執行的函式。當到達截止時間後,它呼叫 cancel 方法處理上下文,此方法會關閉上下文的 done 通道並設定上下文的 timer 屬性為 nil。

done 通道的關閉有效地取消了上下文,使我們的 slowapicall 函式終止了它的執行。這就是 timeouthandler 終止耗時長的處理程序的原理。

(如果你想閱讀上面提到的原始碼,你可以去看`cancelctx` 型別[15]`timerctx` 型別[16]

程序上下文和中斷上下文

程序上下文和中斷上下文是作業系統中很重要的兩個概念,這兩個概念在作業系統課程中不斷被提及,是最經常接觸 看上去很懂但又說不清楚到底怎麼回事。造成這種局面的原因,可能是原來接觸到的作業系統課程的教學總停留在一種淺層次的理論層面上,沒有深入去研究。處理器總處於以下狀態中的一種 核心態,執行於程序上下文,...

程序上下文和中斷上下文

程序上下文是一種核心所處的操作模式,此時核心代表程序執行 例如執行系統呼叫或執行核心執行緒。上下文context 上下文簡單說來就是乙個環境,相對於程序而言,就是程序執行時的環境。具體來說就是各個變數和資料,包括所有的暫存器變數 程序開啟的檔案 記憶體資訊等。乙個程序的上下文可以分為三個部分 使用者...

程序上下文和中斷上下文

核心空間和使用者空間是現代作業系統的兩種工作模式,核心模組執行在核心空間,而使用者態應用程式執行在使用者空間。它們代表不同的級別,而對系統資源具有不同的訪問許可權。核心模組執行在最高端別 核心態 這個級下所有的操作都受系統信任,而應用程式執行在較低級別 使用者態 在這個級別,處理器控制著對硬體的直接...