2017-10-10 3 views
2

채널에 객체를 추가하려면 go-routine을 가지고 있습니다. 그런 다음 채널 객체를 처리하기 위해 go-routines을 가지고 있습니다. 처리는 배열에 객체를 추가하는 것입니다. 그러나 몇 번에, 최종 배열에서 객체가 누락됩니다. 그래서 나는 어떤 시점에서 물체를 수집하기 위해 채널이 멈추는 것으로 가정하고 있습니다. 내가 루틴을 동기화 할 sync 라이브러리를 사용하고채널에서 모든 객체를 수집하지 않는 루틴을 실행하십시오

package main 

import (
    "log" 
    "sync" 
) 

func main() { 
    j := 0 
    for { 
     if j == 10 { 
      break 
     } 
     wg := sync.WaitGroup{} 
     months := []string{"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul"} 
     hits := make(chan string) 
     i := 0 
     wg.Add(1) 
     go func() { 
      defer close(hits) 
      for { 
       if i == 25 { 
        wg.Done() 
        return 
       } 
       for _, month := range months { 
        hits <- month 
       } 
       i++ 
      } 
     }() 

     temp := []string{} 
     for updateWorker := 1; updateWorker <= 4; updateWorker++ { 
      wg.Add(1) 
      go func() { 
       for hit := range hits { 
        temp = append(temp, hit) 
       } 
       wg.Done() 
       return 
      }() 
     } 

     wg.Wait() 

     log.Printf("length of temp %+v\n", len(temp)) 
     j++ 
    } 
} 

: 나는 다음과 같은 코드가 있습니다. 출력이 일관되는지 테스트하기 위해 동일한 프로세스를 10 번 반복합니다. 다음과 같은 출력을 기대합니다 :

length of temp 175 

7 개월 문자열을 25 회 보내므로 175입니다. 하지만 출력이 175 미만인 이유는 무엇인지 모릅니다. 나는 일과 관련하여 초보자 다. 아무도 여기 이유를 찾는데 도와 주실 수 있습니까? 감사.

답변

4

문제는 updateWorker goroutines 모두 (원경 좋지)를 hits 채널로부터 결과를 수집하는 것이 있으며, 이들은 모두 temp 로컬 변수 동기화에 결과를 저장한다. 이건 괜찮지 않아.

여러 goroutines (모든 변수 중 하나 이상이 쓰기 인 경우)에서 모든 변수에 액세스 할 수 있어야합니다.

경주 감지기가 활성화 된 상태에서 실행하면 데이터 경주 (go run -race app.go)에 대해 비명을 지릅니다. 우리 앱의 단일 데이터 레이스 소스를 제거하기 때문에, 1 updateWorker goroutines의 수를 줄일 경우

그것은 바로 올바른 결과를 얻을 수 :

for updateWorker := 1; updateWorker <= 1; updateWorker++ { 
    // ... 
} 

여러 updateWorker goroutines을 유지하려면, 자신의 공유 된 temp 변수에 대한 액세스는 동기화되어야합니다. sync.Mutex 함께

:

temp := []string{} 
mux := sync.Mutex{} 
for updateWorker := 1; updateWorker <= 4; updateWorker++ { 
    wg.Add(1) 
    go func() { 
     for hit := range hits { 
      mux.Lock() 
      temp = append(temp, hit) 
      mux.Unlock() 
     } 
     wg.Done() 
     return 
    }() 
} 

은이 간단한 실시 예에서하면 (잠금) 상기 동기화 심지어 하나만 갖는 비해 덜 확대됨하게 첨가 여러 updateWorker goroutines를 이용하여 아무것도 얻을 없다는 것을 유의 .

제대로 배포하고 결과를 수집하려면이 답변을 확인하십시오. Is this an idiomatic worker thread pool in Go?

관련 문제