Golang-Schnittstelle für gleichzeitige Anforderungen

WBOY
Freigeben: 2023-05-10 11:58:06
Original
1223 Leute haben es durchsucht

Go-Sprache ist eine Programmiersprache, die sich sehr gut für die gleichzeitige Programmierung eignet. Ihre Leistung wird gut genutzt, wenn Dienste oder Anwendungen mit hoher Parallelität implementiert werden. In der täglichen Entwicklung können Szenarien auftreten, die gleichzeitige Anforderungsschnittstellen oder die gleichzeitige Verarbeitung großer Datenmengen erfordern. In diesem Artikel wird erläutert, wie gleichzeitige Anforderungsschnittstellen in Golang implementiert werden.

Szenarien für gleichzeitige Anforderungsschnittstellen

In der tatsächlichen Entwicklung können wir auf Szenarien stoßen, in denen wir eine Schnittstelle anfordern und Antwortdaten erhalten müssen, wie zum Beispiel:

  • Produktdaten auf einer Website abrufen.
  • Erhalten Sie Daten von verschiedenen API-Schnittstellen und präsentieren Sie diese in einer Zusammenfassung.
  • Fordern Sie mehrere Datenquellen gleichzeitig an, um eine schnelle Datenerfassung zu ermöglichen.

Wenn Sie in einem einzelnen Thread mehrere Schnittstellen anfordern müssen, müssen Sie eine Schnittstellenanforderung abschließen, bevor Sie eine andere Schnittstelle anfordern, was dazu führt, dass der gesamte Prozess langsam wird. Im Gegenteil: Durch die Verwendung der Schnittstelle für gleichzeitige Anforderungen können mehrere Anforderungen gleichzeitig initiiert werden, wodurch die Anforderungseffizienz erheblich verbessert wird.

Goroutine Concurrency Processing

Goroutine ist eine spezielle Funktion in der Go-Sprache, die in einem speziellen Thread parallel zum Hauptthread ausgeführt werden kann. Mehrere gleichzeitig ausgeführte Goroutinen können mehrere Schnittstellen gleichzeitig anfordern und nach Abschluss der Anforderung eine Datenintegrationsverarbeitung durchführen. Die gleichzeitige Verwendung von Goroutinen ist relativ einfach zu implementieren und kann über das Schlüsselwort go erreicht werden.

WaitGroup steuert Goroutine

In der tatsächlichen Entwicklung stellen wir möglicherweise fest, dass einige Coroutinen zeitaufwändiger sind und möglicherweise mehr Zeit benötigen, um Ergebnisse zurückzugeben. In diesem Fall müssen wir warten, bis die Coroutine das Ergebnis zurückgibt, und die anschließende Verarbeitung durchführen. Zu diesem Zeitpunkt müssen wir sync.WaitGroup verwenden, um die Anzahl der Goroutinen zu steuern und sicherzustellen, dass alle Anfragen Antwortergebnisse erhalten.

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已经结束
}
Nach dem Login kopieren

Im obigen Code deklarieren wir zunächst eine sync.WaitGroup-Instanz zur Steuerung der Anzahl der Coroutinen. Dann werden in der Funktion main() mehrere Coroutinen durch das Durchlaufen von URLs gestartet. Gleichzeitig wird bei jedem Start einer Coroutine die Methode wg.Add(1) aufgerufen, die diese angibt muss auf ein Coroutine-Finish warten. In diesem Fall wird die Anzahl der in WaitGroup aufgezeichneten wartenden Coroutinen zur Anzahl der URLs in URLs. Dann starten wir in der Zeile go getBody(url) die Coroutine, die die URL anfordert, und rufen dann am Ende der Coroutine die Methode wg.Done() auf. was bedeutet, dass die Coroutine beendet ist. 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)
}
Nach dem Login kopieren

在声明缓冲通道的过程中,我们设置缓冲大小为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)
}
Nach dem Login kopieren

在上面的代码中,我们使用了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()
}
Nach dem Login kopieren

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

Schließlich veranlasst der Aufruf wg.Wait() die Haupt-Coroutine, auf das Ende aller Coroutinen zu warten. 🎜🎜Best Practices für gleichzeitige Anforderungen🎜🎜In der tatsächlichen Entwicklung müssen wir auf einige Details achten, die uns helfen können, die Schnittstelle für gleichzeitige Anforderungen besser zu nutzen. 🎜🎜1. Kontrolle der Anzahl der Parallelitäten🎜🎜Beim gleichzeitigen Anfordern der Schnittstelle müssen wir die Anzahl der Parallelitäten kontrollieren, insbesondere wenn die Anzahl der Schnittstellenanforderungen relativ groß ist, um zu vermeiden, dass der Server zu stark belastet wird. Zeitwünsche. Wir können einen Maximalwert festlegen, um die höchste Anzahl an Parallelitäten sicherzustellen. Wir können den Pufferkanal in Golang verwenden, um die maximale Anzahl von Parallelitäten zu steuern. 🎜rrreee🎜Beim Deklarieren des Pufferkanals setzen wir die Puffergröße auf 5, was bedeutet, dass bis zu 5 Goroutinen gleichzeitig ausgeführt werden können. Dann durchlaufen wir die URLs und fügen dem Kanal den Strukturwert hinzu. 🎜🎜Beim Starten der Goroutine haben wir eine func(url string) als Verarbeitungsfunktion deklariert, um zu vermeiden, dass die maximale Anzahl gleichzeitig laufender Goroutinen 5 übersteigt, und dann getBody(url) aufgerufen )code>Methode. Wenn die Goroutine endet, geben wir ein Signal über den Kanal ab, das anzeigt, dass eine Goroutine beendet wurde – <-ch. 🎜🎜2. Vermeiden Sie das Blockieren von Anforderungen🎜🎜Bei der Erstellung gleichzeitiger Anforderungsschnittstellen müssen wir das Blockieren von Anforderungen vermeiden, das normalerweise auftritt, wenn eine Anforderung längere Zeit nicht antwortet. Wir können dieses Problem mithilfe von context.Context in Golang lösen. Wenn bei der Anfrage eine Zeitüberschreitung auftritt, brechen Sie die blockierte Anfrage ab. 🎜rrreee🎜Im obigen Code haben wir die Methode context.WithTimeout verwendet, um einen Anforderungskontext zu erstellen, dessen Timeout auf 5 Sekunden eingestellt ist, z. B. http://httpsstat.us/200?sleep=8000 , diese Anfrage benötigt 8 Sekunden, um Daten zurückzugeben. Anschließend erstellen wir mithilfe des Anforderungskontexts mithilfe der Methode http.NewRequestWithContext eine Anforderung. Beim Senden einer Anfrage verwenden wir http.DefaultClient, um die Anfrage zu initiieren. Wenn der Antwortstatuscode schließlich 200 ist, werden die Antwortdaten ausgegeben. 🎜🎜Wenn die Anfrage abläuft, wird der Anfragelink direkt geschlossen. Zu diesem Zeitpunkt erhalten wir die Fehlermeldung „Kontextfrist überschritten“. 🎜🎜3. Vermeiden Sie wiederholte Anfragen🎜🎜Beim Anfordern einer Schnittstelle kann es zu wiederholten Anfragen für dieselbe Schnittstelle kommen. In diesem Fall sollten wir vermeiden, wiederholt dieselbe Schnittstelle anzufordern, da dies wertvolle Zeit und Ressourcen verschwendet. Wir können dieses Problem mit sync.Map in Golang lösen. 🎜rrreee🎜Im obigen Code verwenden wir eine sync.Map, um sicherzustellen, dass die URL nur einmal angefordert wird. In der doGet-Coroutine verwenden wir m.LoadOrStore(url, true), um festzustellen, ob die URL angefordert wurde. Wenn sie angefordert wurde, verlässt return die Coroutine direkt. . Andernfalls initiieren wir eine http.Get-Anfrage und drucken die Antwortdaten im Protokoll aus. Schließlich verwenden wir die Methode wg.Done(), um zu markieren, dass die Coroutine beendet wurde. 🎜

Zusammenfassung

In diesem Artikel wird erläutert, wie Sie mit Golang die Schnittstelle für gleichzeitige Anforderungen implementieren. Steuern Sie die Anzahl der Parallelitäten mithilfe der Goroutine-Parallelitätsverarbeitung, der WaitGroup-Coroutinensteuerung und Pufferkanälen. Vermeiden Sie das Blockieren von Anforderungen, indem Sie im Anforderungskontext eine Zeitüberschreitung festlegen, und verwenden Sie sync.Map, um eine Duplizierung von Anforderungen zu vermeiden. Durch den Einsatz dieser Technologien können wir die Effizienz der Anforderungsschnittstelle erheblich verbessern, die Codierungseffizienz und die Programmiererfahrung verbessern.

Das obige ist der detaillierte Inhalt vonGolang-Schnittstelle für gleichzeitige Anforderungen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Quelle:php.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage
Über uns Haftungsausschluss Sitemap
Chinesische PHP-Website:Online-PHP-Schulung für das Gemeinwohl,Helfen Sie PHP-Lernenden, sich schnell weiterzuentwickeln!