>백엔드 개발 >Golang >golang 동시 요청 인터페이스

golang 동시 요청 인터페이스

WBOY
WBOY원래의
2023-05-10 11:58:061372검색

Go 언어는 동시성 프로그래밍에 매우 적합한 프로그래밍 언어입니다. 동시성이 높은 서비스나 애플리케이션을 구현할 때 그 성능이 잘 활용됩니다. 일상적인 개발에서 동시 요청 인터페이스나 대량 데이터의 동시 처리가 필요한 시나리오에 직면할 수 있습니다. 이 기사에서는 golang에서 동시 요청 인터페이스를 구현하는 방법을 소개합니다.

동시 요청 인터페이스 시나리오

실제 개발에서는 다음과 같이 인터페이스를 요청하고 응답 데이터를 얻어야 하는 시나리오에 직면할 수 있습니다.

  • 웹 사이트에서 제품 데이터 가져오기.
  • 다양한 API 인터페이스에서 데이터를 가져와 요약으로 표시합니다.
  • 빠른 데이터 수집을 위해 여러 데이터 소스를 동시에 요청하세요.

단일 스레드에서 여러 인터페이스를 요청해야 하는 경우 다른 인터페이스를 요청하기 전에 하나의 인터페이스 요청을 완료해야 하므로 전체 프로세스가 느려집니다. 반대로 동시 요청 인터페이스를 사용하면 동시에 여러 요청을 시작할 수 있어 요청 효율성이 크게 향상됩니다.

고루틴 동시 처리

고루틴은 메인 스레드와 병렬로 특수 스레드에서 실행될 수 있는 Go 언어의 특수 함수입니다. 동시에 실행되는 여러 고루틴은 동시에 여러 인터페이스를 요청할 수 있으며, 요청이 완료된 후 데이터 통합 ​​처리를 수행할 수 있습니다. 고루틴을 동시에 사용하는 것은 상대적으로 구현하기 쉽고 go 키워드를 통해 달성할 수 있습니다.

WaitGroup은 고루틴을 제어합니다

실제 개발에서 일부 코루틴은 시간이 더 많이 걸리고 결과를 반환하는 데 더 많은 시간이 걸릴 수 있습니다. 이 경우 코루틴이 결과를 반환하고 후속 처리를 수행할 때까지 기다려야 합니다. 이때 모든 요청이 응답 결과를 받을 수 있도록 sync.WaitGroup을 사용하여 고루틴 수를 제어해야 합니다.

package main

import (
    "fmt"
    "io/ioutil"
    "net/http"
    "sync"
)

var wg sync.WaitGroup // 声明一个sync.WaitGroup实例,用于协程控制

func main() {
    urls := []string{"https://www.baidu.com", "https://www.qq.com", "https://www.taobao.com", "https://www.jd.com", "https://www.mi.com"}

    // 通过遍历urls,启动goroutine
    for _, url := range urls {
        wg.Add(1) // 添加一个goroutine
        go getBody(url)
    }

    wg.Wait() // 等待所有goroutine结束
}

// getBody用于获取传入url的响应结果,并打印。
func getBody(url string) {
    resp, err := http.Get(url) // 发起http GET请求
    if err != nil {
        fmt.Println(err)
        return
    }
    defer resp.Body.Close()
    body, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Printf("url: %s, contents:
%s
", url, string(body))
    wg.Done() // 相当于wg.Add(-1),标志该goroutine已经结束
}

위 코드에서는 먼저 코루틴 수를 제어하기 위한 sync.WaitGroup 인스턴스를 선언합니다. 그런 다음 main() 함수에서 URL을 순회하여 여러 코루틴이 시작됩니다. 동시에 코루틴이 시작될 때마다 wg.Add(1) 메서드가 호출되어 하나를 나타냅니다. 코루틴이 완료될 때까지 기다려야 합니다. 이 경우 WaitGroup에 기록된 대기 코루틴의 개수는 URL의 URL 개수가 됩니다. 그런 다음 go getBody(url) 줄에서 URL을 요청하는 코루틴을 시작한 다음 코루틴 끝에서 wg.Done() 메서드를 호출합니다. 이는 코루틴이 종료되었음을 의미합니다. main()函数中,通过遍历urls启动了多个协程,同时每次启动协程时,都会调用wg.Add(1)方法,表示需要等待一个协程完成。这样的话,WaitGroup中记录的等待的协程数量就会变成urls中url数量。然后在go getBody(url)这一行,我们启动了请求url的协程,然后在协程结束的时候调用了wg.Done()方法,表示该协程已经结束。

最后,wg.Wait()调用使主协程等待所有协程结束。

并发请求的最佳实践

在实际开发中,我们需要注意一些细节,这些细节可以帮助我们更好地使用并发请求接口。

一、并发数量的控制

在并发请求接口的时候,我们需要控制并发的数量,特别是当接口请求数量比较大时,避免一次性请求使服务器受到太大压力。我们可以设立一个最大值,这样可以保证并发的最高数量。我们可以使用golang中的缓冲通道实现最大并发数的控制。

ch := make(chan struct{}, 5) // 声明一个缓冲通道,大小为5,控制并发数量为5

for _, url := range urls {
    ch <- struct{}{} // 把协程数量放在通道里
    wg.Add(1)  // 添加一个goroutine
    go func(url string) {
        defer wg.Done()
        getBody(url)
        <-ch // 从通道里取出一个值,表示这个协程已经结束
    }(url)
}

在声明缓冲通道的过程中,我们设置缓冲大小为5,表示最多同时运行5个goroutine,接着我们遍历urls,向通道中加入结构体值。

在启动goroutine的时候,我们声明了一个func(url string)为处理函数,避免同时运行goroutine的最大数量超过5个,然后调用getBody(url)方法。在goroutine结束的时候,我们通过通道释放一个信号,表示有一个goroutine结束了——<-ch

二、避免请求阻塞

在进行并发请求接口的时候,我们需要避免请求阻塞,通常出现在在一个请求长时间没有相应时。我们可以使用Golang中的context.Context解决这个问题。如果请求超时,则取消阻塞的请求。

url := "https://httpstat.us/200?sleep=8000"

ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*5000) // 告诉请求,5秒之后自动取消

defer cancel()

req, err := http.NewRequestWithContext(ctx, "GET", url, nil) // 使用请求上下文

if err != nil {
    log.Fatal(err)
}

client := http.DefaultClient
resp, err := client.Do(req) // 发起请求
if err != nil {
    log.Fatal(err)
}

if resp.StatusCode == http.StatusOK {
    contents, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("%s
", contents)
}

在上面的代码中,我们使用了context.WithTimeout方法创建了一个请求上下文,其timeout设置为5秒,例如http://httpstat.us/200?sleep=8000,这个请求需要8秒才能返回数据。然后我们使用http.NewRequestWithContext方法创建一个使用请求上下文的请求。在发送请求时,我们使用http.DefaultClient发起请求。最后,如果响应状态码是200,则输出响应数据。

当请求超时时,请求链路就会被直接关掉。这时我们会受到“context deadline exceeded”错误的提示。

三、避免请求重复

在请求接口时,可能会遇到重复请求同一个接口的情况,在这种情况下,我们应该避免重复请求同一个接口,这会浪费宝贵的时间和资源。我们可以使用Golang中的sync.Map解决这个问题。

var m = sync.Map{}

url := "https://httpbin.org/get"

wg.Add(2)
go doGet(url, &m, &wg)
go doGet(url, &m, &wg)

wg.Wait()

func doGet(url string, m *sync.Map, wg *sync.WaitGroup) {
    _, loaded := m.LoadOrStore(url, true) // 表示url已经被请求过,如果已存在,则直接返回,否则返回false并储存

    if loaded {
        fmt.Printf("url %s already requested.
", url)
        wg.Done()
        return
    }

    resp, err := http.Get(url)
    if err != nil {
        log.Fatal(err)
    }

    defer resp.Body.Close()
    contents, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("%s
", contents)
    wg.Done()
}

在上面的代码中,我们使用了一个sync.Map来保证url只被请求一次。在doGet协程中,我们使用m.LoadOrStore(url, true)来判断url是否已经被请求过,如果请求过了,就return直接退出协程。否则,我们发起http.Get请求并在log中打印响应数据。最后,我们通过wg.Done()

마지막으로 wg.Wait() 호출은 기본 코루틴이 모든 코루틴이 끝날 때까지 기다리게 합니다. 🎜🎜동시 요청 모범 사례🎜🎜실제 개발에서는 동시 요청 인터페이스를 더 잘 사용하는 데 도움이 될 수 있는 몇 가지 세부 사항에 주의를 기울여야 합니다. 🎜🎜1. 동시성 수 제어🎜🎜인터페이스를 동시에 요청할 때, 특히 인터페이스 요청 수가 상대적으로 많은 경우 동시성 수를 제어해야 합니다. 시간 요청. 최대 동시성을 보장하기 위해 최대값을 설정할 수 있습니다. golang의 버퍼 채널을 사용하여 최대 동시성 수를 제어할 수 있습니다. 🎜rrreee🎜버퍼 채널을 선언하는 과정에서 버퍼 크기를 5로 설정했는데, 이는 최대 5개의 고루틴이 동시에 실행될 수 있음을 의미합니다. 그런 다음 URL을 탐색하고 채널에 구조 값을 추가합니다. 🎜🎜고루틴을 시작할 때 동시에 실행되는 최대 고루틴 수가 5개를 초과하지 않도록 처리 함수로 func(url string)을 선언한 다음 getBody(url)을 호출했습니다. )code>메서드. 고루틴이 종료되면 채널을 통해 신호를 방출하여 고루틴이 종료되었음을 나타냅니다(<-ch). 🎜🎜2. 요청 차단 방지🎜🎜 동시 요청 인터페이스를 만들 때 일반적으로 요청이 오랫동안 응답하지 않을 때 발생하는 요청 차단을 방지해야 합니다. Golang의 context.Context를 사용하여 이 문제를 해결할 수 있습니다. 요청 시간이 초과되면 차단된 요청을 취소하세요. 🎜rrreee🎜위 코드에서는 context.WithTimeout 메서드를 사용하여 http://httpstat.us/200?sleep=8000과 같이 시간 초과가 5초로 설정된 요청 컨텍스트를 생성했습니다. , 이 요청은 데이터를 반환하는 데 8초가 걸립니다. 그런 다음 http.NewRequestWithContext 메소드를 사용하여 요청 컨텍스트를 사용하여 요청을 생성합니다. 요청을 보낼 때 http.DefaultClient를 사용하여 요청을 시작합니다. 마지막으로 응답 상태 코드가 200이면 응답 데이터가 출력됩니다. 🎜🎜요청 시간이 초과되면 요청 링크가 바로 종료됩니다. 이때 "컨텍스트 기한 초과" 오류 메시지가 표시됩니다. 🎜🎜3. 반복적인 요청을 피하세요🎜🎜인터페이스를 요청할 때 동일한 인터페이스에 대한 반복적인 요청이 발생할 수 있습니다. 이 경우 동일한 인터페이스를 반복적으로 요청하는 것은 귀중한 시간과 리소스를 낭비하지 않도록 해야 합니다. Golang의 sync.Map을 사용하여 이 문제를 해결할 수 있습니다. 🎜rrreee🎜위 코드에서는 sync.Map을 사용하여 URL이 한 번만 요청되도록 합니다. doGet 코루틴에서는 m.LoadOrStore(url, true)를 사용하여 URL이 요청되었는지 확인합니다. 요청된 경우 return은 코루틴을 직접 종료합니다. . 그렇지 않으면 http.Get 요청을 시작하고 로그에 응답 데이터를 인쇄합니다. 마지막으로 wg.Done() 메서드를 사용하여 코루틴이 종료되었음을 표시합니다. 🎜

요약

이 글에서는 golang을 사용하여 동시 요청 인터페이스를 구현하는 방법을 소개합니다. 고루틴 동시성 처리, WaitGroup 코루틴 제어 및 버퍼 채널을 사용하여 동시성 수를 제어합니다. 요청 컨텍스트에서 시간 제한을 설정하여 요청 차단을 방지하고, 요청 중복을 방지하려면 sync.Map을 사용하세요. 이러한 기술을 사용함으로써 우리는 요청 인터페이스의 효율성을 크게 향상시키고 코딩 효율성과 프로그래밍 경험을 향상시킬 수 있습니다.

위 내용은 golang 동시 요청 인터페이스의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.