ホームページ  >  記事  >  バックエンド開発  >  Golangの未来・約束について

Golangの未来・約束について

藏色散人
藏色散人転載
2021-04-15 14:33:522711ブラウズ

以下は golang の Golang での未来/約束を紹介するチュートリアル コラムです。

Golangの未来・約束について

現在、アプリケーション実行における最も一般的なボトルネックはネットワーク リクエストです。ネットワーク要求には数ミリ秒しかかかりませんが、応答の待機には 100 倍の時間がかかります。したがって、複数のネットワーク リクエストを実行する場合、それらをすべて並行して実行することが、待ち時間を短縮するための最良のオプションです。 Future/Promiseはその目的を達成するための手段の一つです。

将来とは、「将来」何か (通常はネットワーク リクエストの結果) が必要であるが、そのようなリクエストを今開始する必要があり、リクエストは非同期で実行されることを意味します。別の言い方をすると、バックグラウンドで非同期リクエストを実行する必要があります。

Future/Promise パターンには、複数の言語で対応する実装があります。たとえば、ES2015 には Promise と async-await があり、Scala には組み込みの Future があり、最後に、Golang には同様の機能を実現する goroutine と Channel があります。簡単な実装を以下に示します。

//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 バックグラウンドで非同期に実行されています。 main メソッドは、他の Future をトリガーするなど、他のコードを引き続き実行できます。結果が必要な場合は、チャネルから結果を読み取る必要があります。 http リクエストが返されていない場合、現在のゴルーチンは結果が返されるまでブロックされます。

ただし、上記の方法にはまだいくつかの制限があります。エラーは返せません。上記の例では、http リクエストでエラーが発生した場合、body の値は nil/empty になります。ただし、チャネルは 1 つの値しか返せないため、返された 2 つの結果をラップする別の構造体を作成する必要があります。

変更後の結果:

// 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
    }
}

このメソッドは 2 つの結果を返し、最初のメソッドの制限を解決します。使用すると、次のようになります。

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 メソッドを呼び出すと、ルーム内の多くのチャネル トリックが実行されます。汎用的な目的を達成するために、[]buyte->interface{}->[]byte からの型変換があります。エラーが発生すると、ランタイム panic がトリガーされます。

以上がGolangの未来・約束についての詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はsegmentfault.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。