고 루틴에서 반환 값 잡기


83

아래 코드는 '예기치 않은 이동'이라는 컴파일 오류를 제공합니다.

x := go doSomething(arg)

func doSomething(arg int) int{
    ...
    return my_int_value
}

고 루틴을 사용하지 않고 정상적으로 함수를 호출하면 반환 값을 가져올 수 있습니다. 또는 채널 등을 사용할 수 있습니다.

내 질문은 고 루틴에서 이와 같은 반환 값을 가져올 수없는 이유입니다.


7
당신이 그것을 반환 할 채널을 사용할 수 있습니다
rogerdpack

왜 반환 a를 goroutine 가치를 갖는 수 있습니까
samala srinath

1
사용중인 함수의 API를 변경해야하는 @rogerdpack. 당신의 자신의 아니라면 당신은 래퍼 함수를해야 할 수도 있으므로
데이비드 Callanan

답변:


67

엄격한 대답은 그렇게 할 수 있다는 것입니다. 그것은 아마도 좋은 생각이 아닐 것입니다. 이를 수행하는 코드는 다음과 같습니다.

var x int
go func() {
    x = doSomething()
}()

이것은 계산 doSomething()한 다음 결과를에 할당 할 새로운 고 루틴을 생성합니다 x. 문제는 : x원래 고 루틴에서 어떻게 사용할 것인가? 경합 상태가 없도록 생성 된 고 루틴이 완료되었는지 확인하고 싶을 것입니다. 하지만 그렇게하려면 고 루틴과 통신 할 방법이 필요합니다. 그렇게 할 수있는 방법이 있다면 값을 다시 보내는 데 사용하는 것이 어떻습니까?


6
완료되었는지 확인하고 기다릴 수 있도록 WaitGroup을 추가 할 수 있습니다. 그러나 당신이 말했듯이, 채널은 그것을하는 방법이 아닙니다.
Not_a_Golfer 2014 년

1
이 아닌 return이입니다 assign, 표준
Nidhin 데이비드

95

고 루틴에서 반환 값을 가져와 변수에 할당 할 수없는 이유는 무엇입니까?

goroutine을 (비동기 적으로) 실행하고 함수에서 반환 값을 가져 오는 것은 본질적으로 모순되는 작업입니다. 당신이 말할 때 go당신은 의미 "비동기 적으로 그것을"또는 간단 : "할 일에 이동 완료 될 기능 실행을 위해 기다릴 수 없다". 그러나 함수 반환 값을 변수에 할당하면 변수 내에이 값이있을 것으로 예상됩니다. 그래서 당신이 그렇게 할 때 당신은 x := go doSomething(arg)"계속, 함수를 기다리지 마세요! Wait-wait-wait! 반환 된 값이 필요합니다. x바로 아래 줄의 var에서 접근 가능 합니다!"

채널

고 루틴에서 값을 가져 오는 가장 자연스러운 방법은 채널입니다. 채널은 동시 고 루틴을 연결하는 파이프입니다. 한 고 루틴에서 채널로 값을 보내고 다른 고 루틴이나 동기 함수에서 해당 값을 수신 할 수 있습니다. 다음을 사용하여 동시성을 깨지 않고 goroutine에서 값을 쉽게 얻을 수 있습니다 select.

func main() {

    c1 := make(chan string)
    c2 := make(chan string)

    go func() {
        time.Sleep(time.Second * 1)
        c1 <- "one"
    }()
    go func() {
        time.Sleep(time.Second * 2)
        c2 <- "two"
    }()

    for i := 0; i < 2; i++ {
        // Await both of these values
        // simultaneously, printing each one as it arrives.
        select {
        case msg1 := <-c1:
            fmt.Println("received", msg1)
        case msg2 := <-c2:
            fmt.Println("received", msg2)
        } 
    }
}

예제는 Go By Example에서 가져온 것입니다.

CSP 및 메시지 전달

Go는 대체로 CSP 이론을 기반으로 합니다. 위의 순진한 설명은 CSP 측면에서 정확하게 설명 될 수 있습니다 (물론 범위를 벗어난 것으로 생각합니다). 적어도 RAD이기 때문에 CSP 이론에 익숙해지는 것이 좋습니다. 이 짧은 인용문은 생각의 방향을 제시합니다.

이름에서 알 수 있듯이 CSP 는 독립적으로 작동 하고 메시지 전달 통신을 통해서만 서로 상호 작용 하는 구성 요소 프로세스 측면에서 시스템을 설명 할 수 있습니다 .

컴퓨터 과학에서 메시지 전달은 메시지를 프로세스에 보내고 프로세스 및 지원 인프라에 의존하여 실행할 실제 코드를 선택하고 호출합니다. 메시지 전달은 프로세스, 서브 루틴 또는 함수가 이름으로 직접 호출되는 기존 프로그래밍과 다릅니다.


9

go키워드 의 아이디어는 doSomething 함수를 비동기 적으로 실행하고 결과를 기다리지 않고 현재 고 루틴을 계속하는 것입니다. 마치 Bash 쉘에서 명령 뒤에 '&'가있는 명령을 실행하는 것과 같습니다. 하고 싶다면

x := doSomething(arg)
// Now do something with x

그런 다음 doSomething이 완료 될 때까지 차단할 현재 고 루틴이 필요합니다. 그렇다면 현재 고 루틴 에서 doSomething 호출하지 않는 이유 는 무엇입니까? 다른 옵션 (예 : doSomething은 현재 고 루틴이 값을받는 채널에 결과를 게시 할 수 있음)이 있지만 단순히 doSomething을 호출하고 그 결과를 변수에 할당하는 것이 훨씬 간단합니다.


0

Go 제작자가 선택한 디자인입니다. -이의 I / O 작업이 비동기의 값을 표현하는 추상화 / API를 훨씬이다 promise, future, async/await, callback, observable-, 등이 추상화는 / API를 본질적으로 스케줄링의 단위에 연결되어 코 루틴은 - 이러한 추상화 / API를 지시하는 방법 코 루틴 ( 또는 더 정확하게는 그들로 표현되는 비동기 I / O의 반환 값)을 구성 할 수 있습니다 .

Go는 비동기 I / O 작업의 반환 값을 나타내는 추상화 / API로 메시지 전달 (일명 channels )을 선택했습니다 . 물론 고 루틴과 채널은 비동기 I / O 작업을 구현할 수있는 구성 가능한 도구를 제공합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.