2016-11-12 4 views
1

Run() 메서드가있는 Hub 구조체가 고유 한 goroutine에서 실행됩니다. 이 방법은 수신 메시지를 순차적으로 처리합니다. 메시지는 여러 프로듀서 (개별 goroutines)로부터 동시에 도착합니다. 물론이 작업을 수행하려면 channel을 사용합니다. 그러나 이제 interface 뒤에 Hub을 숨기고 구현에서 선택할 수 있습니다. 따라서 channel을 단순한 Hub의 입력란으로 사용하는 것은 적절하지 않습니다.함수 호출 뒤에 채널을 숨기는 것이 안전합니까?

package main 
import "fmt" 
import "time" 

type Hub struct { 
    msgs chan string 
} 
func (h *Hub) Run() { 
    for { 
     msg, hasMore := <- h.msgs 
     if !hasMore { 
      return 
     } 
     fmt.Println("hub: msg received", msg) 
    } 
} 
func (h *Hub) SendMsg(msg string) { 
    h.msgs <- msg 
} 

func send(h *Hub, prefix string) { 
    for i := 0; i < 5; i++ { 
     fmt.Println("main: sending msg") 
     h.SendMsg(fmt.Sprintf("%s %d", prefix, i)) 
    } 
} 

func main() { 
    h := &Hub{make(chan string)} 
    go h.Run() 
    for i := 0; i < 10; i++ { 
     go send(h, fmt.Sprintf("msg sender #%d", i)) 
    } 
    time.Sleep(time.Second) 
} 

그래서 난 그냥 h.msgs <- msg를 호출하고있는 나는 HubInterface에 추가 할 수 Hub.SendMsg(msg string) 기능을 도입했습니다. 그리고 Go -newbie로 궁금합니다. 동시성 관점에서 안전합니까? 그렇다면 Go의 일반적인 접근 방식입니까?

놀이터 here.

+3

예. 나는 당신이 그것이 안전하지 않을 수 있다고 믿게 만들 것이 확실하지 않기 때문에 어떻게 대답 할 지 모르겠습니다. – JimB

+0

@JimB, 실제로, 후드에서 작동하는 방법을 잠시 생각한 후에 채널에 쓰는 것이 스레드로부터 안전하다는 대답은 매우 분명하다는 것을 깨달았습니다. –

+1

_ 하나의 채널은 send 문, 수신 작업 및 내장 함수 호출을 추가 동기화없이 원하는 수의 goroutine에 의해 사용할 수 있습니다 ._ 더 자세한 내용은 [채널을 제대로 사용해야하는 경우 뮤텍스를 사용합니까?] (http://stackoverflow.com/questions/34039229/if-i-am-using-channels-properly-should-i-need-to-use-mutexes) – icza

답변

2

채널 전송 의미는 메소드를 전송할 때 변경되지 않습니다. 앤드류의 대답은 성공적으로 보내기 위해서는 채널을 make으로 만들어야한다고 지적했으나, send가 메소드 내부에 있는지 여부에 관계없이 항상 그렇습니다.실수로 nil 채널 무효 Hub 인스턴스와 바람 수 있는지 발신자을 염려되는 경우

는 하나의 접근 방식은 개인 구조체 유형 (hub를)하고 완전히 hub 초기화 반환하는 NewHub() 기능을하는 것입니다 귀하의 인터페이스 유형에 싸서. 구조체는 private이기 때문에 다른 패키지의 코드는 불완전한 struct literal (또는 struct 리터럴)로 초기화하려고 시도 할 수 없습니다. net.IP("HELLO THERE BOB")이 유효 구문, 또는 net.IP{}입니다 :

는 자주 이동에 유효하지 않거나 터무니없는 값을 만들 수 그리고 그 허용있어, 말했다. 따라서 노출하고자하는 것이 더 바람직하다고 생각하면 Hub 유형을 사용하십시오.

-1

쉬운 대답

더 나은 대답은

없음

채널은 알 수없는 이동 루틴에서 데이터를 방출 큰 없습니다. 그들은 그렇게 안전하게하지만, 나는 몇 가지 부분에 조심하는 것이 좋습니다 것입니다. 나열된 예제에서 채널은 소비자가 구조체를 구성하여 생성됩니다 (소비자가 아닌).

소비자가 다음과 같이 허브를 생성한다고 가정하면 &Hub{}입니다. 완벽하게 유효합니다 ... SendMsg()의 모든 호출이 영원히 차단된다는 사실 외에도. 운 좋게도 당신은 그것들을 그들 자신의 일과에 배치했습니다. 그래도 여전히 괜찮아? 잘못된. 당신은 지금 고비를 누출하고 있습니다. 일정 기간 동안 이걸 달릴 때까지 ... Go는 유효한 0 값을 갖도록 권장합니다. 이 경우 &Hub{}은 유효하지 않습니다.

select{}을 통해 SendMsg()이 차단되지 않도록 보장 할 수 있지만 기본 사례 (예 : 데이터 삭제)가 발생할 경우 수행 할 작업을 결정해야합니다. 나쁜 설정보다 많은 이유로 채널이 차단 될 수 있습니다. 나중에 채널에서 읽은 후 단순히 데이터를 인쇄하는 것 이상의 일을한다고 가정 해보십시오. 읽기 속도가 매우 느려지거나 IO가 차단되면 어떻게 될까요? 그런 다음 제작자를 다시 시작합니다.

궁극적으로 채널을 사용하면 동시성에 대해 많이 생각하지 않아도됩니다. 그러나 이것이 높은 처리량의 것이라면 고려해야 할 사항이 많습니다. 프로덕션 코드 인 경우 여기서 API는 SendMsg() 블로킹과 관련되어 있음을 이해해야합니다.

+2

이것은 매우 혼란 스럽습니다. 질문은 채널 보내기 의미가 전송을 함수로 이동하여 변경되는지 여부와 관련된 것이 었습니다. '& Hub {}'는 채널 보내기가 함수 호출 안에 있는지 여부에 상관없이 유효 유형의 전체 정지 값입니다. – twotwotwo