Go에서는 int, struct, 포인터, 인터페이스 등 모든 유형의 값을 채널을 통해 보낼 수 있습니다.
코드 및 예제:
type Data struct { N int } c := make(chan Data) d := Data{N: 1} c <- d // 전체 구조체가 복사됨 p := &Data{N: 3} c2 := make(chan *Data) c2 <- p // 채널을 통해 같은 객체에 대한 포인터가 전송됨
채널을 통해 포인터 필드가 포함된 구조체를 전달하면 - 채널의 양쪽에서 이 필드를 변경할 때 경쟁 상태가 발생할까요?
답변:
예제:
type Box struct { Ptr *int } x := 10 chanBox := make(chan Box) chanBox <- Box{Ptr: &x} // 송신자와 수신자 모두 x에 접근할 수 있음!
이야기
분산 큐에서 자주 "우연한" 실패와 작업 구조체의 불가사의한 값들이 발생했습니다. 채널을 통해 공유 구조체에 대한 포인터가 여러 고루틴에서 동시에 변경되는 것을 발견했습니다. 데이터 복사로 전송 방식을 변경하기로 결정했습니다.
이야기
비동기 메시지 처리는 내부에 공유 배열에 대한 슬라이스 포인터를 가진 구조체들을 다루고 있었습니다. 같은 메모리의 일부가 서로 다른 위치에서 동시에 변경되어 숨겨진 버그와 데이터 손상을 초래했습니다.
이야기
푸시 알림 서비스에서는 채널을 통해 객체에 대한 참조가 전달되었고, 이후 고루틴에서 처리되었습니다. 작업 완료 시점과 채널 닫기가 동시에 발생하면서 일부 구조체가 여전히 수정되어 패닉이나 data race를 유발했습니다. 전송 전에 구조체를 복사하도록 변경하여 도움이 되었습니다.