2012-10-17 5 views
6

지도에서 삭제할 수 있습니다 포함한 동시 작가를 가지고지도 m 이상에 이르기까지,이 스레드 안전하지 이것이 내가 스레드 안전 I로 생각하고이동 범위에서 스레드로부터 안전하지 않은 값을 사용하고 있습니까?

for k, v := range m { ... } 

을 ?:하는 것입니다 다른 가능한 작성자가 값을 v으로 변경하는 것을 방지해야합니다. (뮤텍스를 사용할 때 잠금이 별도의 단계이기 때문에) k이 여전히지도에 있는지 확인하십시오. 예를 들어 :

for k := range m { 
    m.mutex.RLock() 
    v, found := m[k] 
    m.mutex.RUnlock() 
    if found { 
     ... // process v 
    } 
} 

는 (다른 작가 v을 변경하기 전에 m을 쓰기 잠금 가정합니다.) 더 좋은 방법이 있나요?

편집 추가 :지도가 스레드로부터 안전하지 않다는 것을 알고 있습니다. 그러나 Go 규격의 http://golang.org/ref/spec#For_statements ("아직 도달하지 않은지도 항목이 반복 중에 삭제되는 경우"를 검색)에 따르면이 방법은 스레드로부터 안전합니다. 이 페이지는 range을 사용하는 코드가지도에 삽입하거나지도에서 삭제하는 다른 goroutine에 대해 걱정할 필요가 없음을 나타냅니다. 내 질문은,이 thread-safe-ness 읽을 수있는 유일한for k, v := range m 및 다른 스레드 안전 메커니즘을 사용하여 얻을 수 있도록 v 확장합니까? 나는 그것이 작동하지 않는다는 것을 증명하기 위해 앱 크래시를 강제하기 위해 테스트 코드를 만들었지 만, 깔끔하게 스레드 안전하지 않은 코드 (많은 goroutine이 동일한 맵 값을 맹목적으로 수정하지 않고 많은 장소에서 잠금 메커니즘을 수정 함) 추락하자!

+1

그냥 코멘트 (아마 이미 다른 독자들에 대한보다 그것을 알고있는 영업 이익 이하) : http://golang.org/doc/go_faq.html#atomic_maps 응답에 대한 –

답변

9

아니요,지도 작업은 원자/스레드 안전이 아니며 질문에 대한 작성자는 the golang FAQ “Why are map operations not defined to be atomic?”을 가리 킵니다.

액세스를 안전하게하려면 리소스 액세스 토큰의 수단으로 gos channels을 사용하는 것이 좋습니다. 채널은 단순히 토큰을 전달하는 데 사용됩니다. 이를 수정하려는 사용자는 채널에서 차단 또는 차단을 요청할 것입니다. 맵 작업을 마치면 토큰을 다시 채널로 전달합니다.

지도 반복 작업은 충분히 간단하고 짧아야하므로 전체 액세스를 위해 하나의 토큰 만 사용해도됩니다.

그렇지 않은 경우 더 복잡한 작업을 위해 맵을 사용하거나 리소스 소비자가 더 많은 시간을 필요로하는 경우 reader-vs writer-access-token을 구현할 수 있습니다. 따라서 주어진 시간에 한 명의 작성자 만지도에 액세스 할 수 있지만 작성자가 활성화되지 않은 경우 토큰은 여러 개의 독자에게 전달되며지도를 수정하지 않으므로 동시에 읽을 수 있습니다.

채널 소개는 the Effective Go docs on channels을 참조하십시오.

+0

감사합니다! 나는'for k, v : = range m {...} '가 읽기 전용 인 경우'v'에 대해 thread-safe한지 궁금해하기 위해 제 질문을 편집했습니다. Go 스펙은 '범위'가 다른 goroutine이 맵에 삽입되거나 맵에서 삭제되는 한 스레드로부터 안전하다는 것을 나타냅니다. 채널에 대해서는 알고 있지만,'range'를 사용하여'v'를 쓰는 것이 이미 쓰레드에 안전하다면, 그게 전부입니다. – user1744397

+1

[여기]와 같이 좀 더 둘러보고 좋습니다. (https://groups.google.co.kr/forum /? fromgroups = #! searchin/golang-nuts/map $ 20range/golang-nuts/eJqwQLONhLs/3YFEjIe57wMJ), 귀하의 답변이 맞습니다. 스레드로부터 안전하다고 판단되면, 다른 goroutine이 반복되는 동일한 키를 작성 (업데이트, 삭제 또는 수정) 할 경우 '범위'를 사용하기 전에 전체 맵을 잠그는 것이 필요합니다. 위에서 언급 한 Go 스펙의 섹션은 범위를 벗어나는 맵에서 삭제하거나 삽입하는 단일 스레드에 대해 이야기하고 스레드에 * 영향을 미치는 * 방법에 대해 설명합니다. – user1744397

0

concurrent-map을 사용하면 동시성 통증을 처리 할 수 ​​있습니다.

// Create a new map. 
map := cmap.NewConcurretMap() 

// Add item to map, adds "bar" under key "foo" 
map.Add("foo", "bar") 

// Retrieve item from map. 
tmp, ok := map.Get("foo") 

// Checks if item exists 
if ok == true { 
    // Map stores items as interface{}, hence we'll have to cast. 
    bar := tmp.(string) 
} 

// Removes item under key "foo" 
map.Remove("foo") 
관련 문제