2016-09-02 14 views
2

如何從「併發地圖讀取和地圖寫入」的運行時恐慌中恢復?通常延遲恢復似乎不起作用。這是爲什麼?如何從併發映射寫入中恢復?

我知道你不應該在併發環境中使用地圖,但仍然:如何在這裏恢復?

實施例:

package main 

import "time" 

var m = make(map[string]string) 

func main() { 
    go func() { 
     for { 
      m["x"] = "foo" 
     } 
    }() 
    go func() { 
     for { 
      m["x"] = "foo" 
     } 
    }() 

    time.Sleep(1 * time.Second) 
} 

請添加恢復代碼。 :)

回答

12

恢復不起作用,因爲你遇到的不是panicing狀態。

Go 1.6 added地圖檢測的輕量級併發濫用運行:地圖的同時濫用

運行時增加了重量輕,盡力而爲的檢測。與往常一樣,如果一個goroutine正在寫入地圖,則其他goroutine不應該同時讀取或寫入地圖。 如果運行時檢測到這種情況,它會打印診斷並使程序崩潰。找出更多問題的最好方法是運行race detector下的程序,這將更可靠地識別比賽並提供更多細節。

你體驗什麼是運行時的故意撞車,它不是一個panic()調用一個recover()呼叫遞延功能可以阻止的結果。

除阻止併發濫用地圖之外,沒有什麼可以阻止這一點。如果你想離開你的應用程序,它不會崩潰,你可能會在運行時遇到神祕的,未定義的行爲。

+0

感謝您對發行說明的反應。我正在尋找那個。 –

+0

這裏誤導的是堆棧跟蹤指向「/usr/local/go/src/runtime/panic.go:547」中的'dopanic'函數:'dopanic(0)' –

+0

@IgorLankin因爲事情是這樣做與恐慌類似:打印堆棧跟蹤,但應用程序崩潰。你可以在''panic.go'','dopanic_m()'函數的末尾看到這個:'crash()'和'exit()'調用。 – icza

2

不要恢復,用互斥鎖形式包sync保護你的代碼。

package main 

import (
    "sync" 
    "time" 
) 

var m = make(map[string]string) 
var l = sync.Mutex{} 

func main() { 
    go func() { 
     for { 
      l.Lock() 
      m["x"] = "foo" 
      l.Unlock() 
     } 
    }() 
    go func() { 
     for { 
      l.Lock() 
      m["x"] = "foo" 
      l.Unlock() 
     } 
    }() 

    time.Sleep(1 * time.Second) 
} 
+1

這不是問題。問題是爲什麼恢復不起作用。 –