2013-09-23 34 views
1

此問題的一個示例是用戶創建資源並刪除資源。我們將執行操作並增加(遞減)計數器緩存。如何去測試去例程?

在測試中,有時會出現競爭狀態,計數器緩存並未由go例程更新。

編輯:抱歉的混亂,澄清:計數器緩存不在內存中,它實際上是數據庫中的字段。競爭條件不是內存中的變量,實際上goroutine可能會很慢寫入數據庫本身!

我目前在操作後使用1秒睡眠來確保計數器緩存在測試計數器緩存之前已經更新。有沒有另外一種方法來測試沒有任意1秒睡眠的例行程序,以等待去程序完成?

乾杯

+0

一小段代碼示例會很好。我試圖擺脫睡眠和競爭狀態,但無法猜測你的代碼是什麼樣的。假設尚未使用,那麼聽起來像頻道是你需要的。 – miltonb

+1

我第二@米爾頓的觀點。在代碼中引入睡眠以「修復」數據競爭通常不是正確的解決方案。一旦你的系統負載很重,超過一秒鐘就會通過生產,然後睡眠不起作用。安全構建這些系統的唯一方法是同步。同步通常涉及到某個通道使用信號發送安全寫回信號。 –

回答

3

在測試中,有時存在的競爭條件,使計數器緩存沒有被旅途例行更新。我目前在操作之後使用1秒睡眠來確保在測試計數器緩存之前計數器緩存已經被更新。

哎呀,我討厭這麼說,但你做錯了。 Go具有一流的功能,使併發變得輕鬆!如果你正確使用它們,就不可能有競爭條件。

事實上,有一個工具,將detect races for you。我敢打賭,它抱怨你的計劃。

一個簡單的解決方案:

  • 有主程序創建保持計數器的軌道夠程。
  • 該goroutine只會做一個選擇並獲得一個消息來遞增/遞減或讀取計數器。 (如果讀取,它將通過一個通道返回數字)
  • 當您創建/刪除資源時,通過它的通道向goroutine計數器發送適當的消息。
  • 當您想要讀取計數器時,發送消息進行讀取,然後讀取返回通道。

(另一種方法是使用鎖。這將是更高性能的一點點,但更麻煩的編寫,並確保它是正確的。)

+0

對此感到抱歉,澄清一下:計數器緩存不在內存中,它實際上是數據庫中的一個字段。競爭條件不是內存中的變量,實際上goroutine可能會很慢寫入數據庫本身! – samol

+0

@SidneySidaZhang是的,爲此你需要同步。爲此,還有像頻道這樣的工具,如果必須的話,還有鎖。你只能保證你的代碼按照正確的順序執行,如果它是同步的。數據所在的位置並不重要,它是如何獲得重要信息的方式。 – nemo

+0

如果您在寫完結果後需要閱讀結果,則無法在不同的程序中進行寫入和讀取。 – BraveNewCurrency

0

一種解決方案是讓讓你還價只要值 更改,就會更新頻道。通常情況下,通過傳達結果進行同步。例如您 Couter看起來是這樣的:

type Counter struct { 
    value int 
    ValueChange chan int 
} 

func (c *Counter) Change(n int) { 
    c.value += n 
    c.ValueChange <- c.value 
} 

每當Change被調用時,新的值通過通道時和誰是 等待值疏導,並繼續執行,因此與 計數器同步。有了這個代碼,你可以在ValueChange聽這樣的變化:

v := <-c.ValueChange 

同時呼籲c.Change是沒有問題了。

有一個runnable example on play