>  기사  >  백엔드 개발  >  Golang의 미래/약속에 대하여

Golang의 미래/약속에 대하여

藏色散人
藏色散人앞으로
2021-04-15 14:33:522659검색

다음 튜토리얼 칼럼인 golang에서는 Golang의 Future/Promise를 소개하겠습니다. 도움이 필요한 친구들에게 도움이 되길 바랍니다!

Golang의 미래/약속에 대하여

요즘 애플리케이션 실행에서 가장 흔한 병목 현상은 네트워크 요청입니다. 네트워크 요청은 몇 밀리초밖에 걸리지 않지만 응답을 기다리는 데는 100배 더 오래 걸립니다. 따라서 여러 네트워크 요청을 수행하는 경우 모든 요청을 병렬로 실행하는 것이 대기 시간을 줄이는 가장 좋은 옵션입니다. Future/Promise는 이러한 목적을 달성하기 위한 수단 중 하나입니다.

미래는 "미래에"(일반적으로 네트워크 요청의 결과) 무언가가 필요하지만 지금 그러한 요청을 시작해야 하며 이 요청은 비동기적으로 실행된다는 것을 의미합니다. 또는 다르게 말하면 백그라운드에서 비동기 요청을 수행해야 합니다.

Future/Promise 패턴에는 여러 언어로 해당 구현이 있습니다. 예를 들어 ES2015에는 Promise와 async-await가 있고 Scala에는 Future가 내장되어 있으며 마지막으로 Golang에는 유사한 기능을 달성하기 위한 고루틴과 채널이 있습니다. 간단한 구현은 아래와 같습니다.

//RequestFuture, http request promise.
func RequestFuture(url string) <-chan []byte {
    c := make(chan []byte, 1)
    go func() {
        var body []byte
        defer func() {
            c <- body
        }()

        res, err := http.Get(url)
        if err != nil {
            return
        }
        defer res.Body.Close()

        body, _ = ioutil.ReadAll(res.Body)
    }()

    return c
}

func main() {
  future := RequestFuture("https://api.github.com/users/octocat/orgs")
  body := <-future
  log.Printf("reponse length: %d", len(body))
}

RequestFuture 메소드는 채널을 반환합니다. 이때 http 요청은 여전히 ​​goroutine 백그라운드에서 비동기적으로 실행됩니다. 기본 메서드는 다른 Future 트리거 등의 다른 코드를 계속해서 실행할 수 있습니다. 결과가 필요할 때 채널에서 결과를 읽어야 합니다. http 요청이 반환되지 않은 경우 결과가 반환될 때까지 현재 고루틴이 차단됩니다. RequestFuture方法理科返回一个channel,这个时候http请求还在一个goroutine后台异步运行。main方法可以继续执行其他的代码,比如触发其他的Future等。当需要结果的时候,我们需要从channel里读取结果。如果http请求还没有返回的话就会阻塞当前的goroutine,知道结果返回。

然而,以上的方法还有一点局限。错误无法返回。在上面的例子里,如果http请求出现错误的话,body的值会是nil/empty。但是,由于channel只能返回一个值,你需要创建一个单独的struct来包装两个返回的结果。

修改以后的结果:

// RequestFutureV2 return value and error
func RequestFutureV2(url string) func() ([]byte, error) {
    var body []byte
    var err error

    c := make(chan struct{}, 1)
    go func() {
        defer close(c)

        var res *http.Response
        res, err = http.Get(url)
        if err != nil {
            return
        }

        defer res.Body.Close()
        body, err = ioutil.ReadAll(res.Body)
    }()

    return func() ([]byte, error) {
        <-c
        return body, err
    }
}

这个方法返回了两个结果,解决了第一个方法的局限性问题。使用的时候是这样的:

func main() {
    futureV2 := RequestFutureV2("https://api.github.com/users/octocat/orgs")

    // not block
    log.Printf("V2 is this locked again")

    bodyV2, err := futureV2() // block
    if err == nil {
        log.Printf("V2 response length %d\n", len(bodyV2))
    } else {
        log.Printf("V2 error is %v\n", err)
    }
}

上面的修改带来的好处就是futureV2()方法的调用可以是多次的。并且都可以返回同样的结果。

但是,如果你想用这个方法实现很多不同的异步功能,你需要写很多的额外的代码。我们可以写一个util方法来克服这个困难。

// Future boilerplate method
func Future(f func() (interface{}, error)) func() (interface{}, error) {
    var result interface{}
    var err error

    c := make(chan struct{}, 1)
    go func() {
        defer close(c)
        result, err = f()
    }()

    return func() (interface{}, error) {
        <-c
        return result, err
    }
}

调用Future方法的时候会执行房里的很多channel方面的小技巧。为了能够达到通用的目的有一个从[]buyte->interface{}->[]byte그러나 위의 방법에는 여전히 몇 가지 제한 사항이 있습니다. 오류를 반환할 수 없습니다. 위의 예에서 http 요청에 오류가 발생하면 body 값은 nil/empty가 됩니다. 그러나 채널은 하나의 값만 반환할 수 있으므로 반환된 두 결과를 래핑하려면 별도의 구조체를 만들어야 합니다. 수정 후 결과:

rrreee🎜이 메서드는 두 가지 결과를 반환하여 첫 번째 메서드의 한계를 해결합니다. 사용하면 다음과 같습니다. 🎜rrreee🎜위 수정의 장점은 futureV2() 메서드를 여러 번 호출할 수 있다는 것입니다. 그리고 둘 다 동일한 결과를 반환할 수 있습니다. 🎜🎜그러나 이 방법을 사용하여 다양한 비동기 기능을 구현하려면 추가 코드를 많이 작성해야 합니다. 이러한 어려움을 극복하기 위해 util 메소드를 작성할 수 있습니다. 🎜rrreee🎜 Future 메소드를 호출하면 방 안의 여러 채널 트릭이 수행됩니다. 보편적인 목적을 달성하기 위해 []buyte->interface{}->[]byte에서 유형 변환이 있습니다. 오류가 발생하면 런타임 🎜panic🎜이 트리거됩니다. 🎜🎜

위 내용은 Golang의 미래/약속에 대하여의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 segmentfault.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제