2017-02-21 15 views
6

在Golang中,我相當新的意圖下游通過contexts其他方法和功能。我明白context是如何工作的,它是如何使用的,它是如何保持其價值的,它如何與父母context及其行爲有關 - 我只是不明白爲什麼首先使用上下文。如何將context.WithDeadline或一個簡單的定時器之間做出選擇?

在一個更具體的例子中,這是這個問題的實際原因,在我工作的公司中,我們發現了一些由於邊緣情況而經常發生的非常長時間的查詢。

考慮到我們的限制,我們決定採取一個明顯的解決方案,直到我們投入時間解決根本原因,那就是殺掉超過5分鐘的查詢。

運行我們交易的方法接受最初在API調用中啓動的context。這是context一路向下傳遞到交易功能。在那一刻,我發現2個解決方案,以殺死查詢:

1)使用新的上下文:

  • 啓動一個新的context.WithTimeout(ctx, time.Duration(5 * time.Minute))

  • 觀看Done通道在go routine並殺死交易當出現信號時

  • 如果事務及時成功完成,則只需cancel環境並按預期提交事務。

2)使用Timer

  • 創建Timer 5分鐘持續時間
  • 如果時間已經過去,殺死交易
  • 否則,提交事務。

從邏輯上講,它們是相同的解決方案,但是,何時以及如何決定是否使用context有規定期限或好老Timer

+2

作爲1.8 ['數據庫/ sql'](https://golang.org/pkg/database/sql /#DB.BeginTx0Z)支持使用上下文。我想這可能會簡化你的決定。 – jmaloney

回答

2

答案在於context.Contexttime.Timer如何傳遞(取消)信號。

context.Context讓你通過Context.Done()方法將使用夠程時,應終止關閉接入信道。

time.Timer,您可以訪問一個通道在Timer.C結構領域上的值將在給定的時間段之後發送(該值將是當前的時間,但在這裏並不重要)。

在那裏,重點突出。通道關閉可以通過任何數目的夠程,以及無限的次數觀察到。Spec: Receive operator:

甲接收在closed信道操作可總是立即進行,得到的元素類型的zero value任何先前發送的值之後已經收到。

因此,一個Context可用於信號取消任意數量的goroutines和地方。 A Timer只能用於發送一個目標,即從其通道接收值的目標。如果多個客戶正在收聽或嘗試從其頻道收到,則只有一個客戶會很幸運地收到它。

此外,如果您使用/處理已支持/期望context.Context的代碼,那麼它不應該成爲使用的問題。 Go 1.8還添加了more context support。有上下文支持的database/sql包有significant additions;包括DB.BeginTx()

提供的上下文用於事務提交或回滾之前。如果上下文被取消,sql包將回滾事務。如果提供給BeginTx的上下文被取消,則Tx.Commit將返回錯誤。

這是主用的context.Context:攜帶跨越API邊界的最後期限和信號消除,並且它在併發安全的方式進行(如Context值是不可變的,並且信道也可用於同時使用安全,數據競賽不會發生,通過設計;更多在此:If I am using channels properly should I need to use mutexes?)。

相關博客文章:

The Go Blog: Go Concurrency Patterns: Context

Pitfalls of context values and how to avoid or mitigate them in Go

Dave Cheney: Context is for cancelation

相關問題