用GoRoutines高性能同時進行多個Api呼叫
轉載請注明來源:https://janrs.com/2023/03/用goroutines同時進行多個api呼叫/
Golang是高效的,非常高效,這種效率在很大程度上要歸功于它在處理并發性問題時的獨特抽象,例如,Java將其執行緒映射為作業系統執行緒,而Go使用自己的goroutines調度器將其輕量級goroutines從作業系統執行緒中進一步抽象出來,簡而言之,Golang在使用作業系統執行緒方面非常節儉;如果一個goroutine被阻塞了,Go的調度器會在它的位置上切換另一個goroutine,以盡可能地保持執行緒的忙碌,由于每個CPU核心處理的執行緒數量有限(而且產生新的執行緒是很昂貴的),保持這些執行緒的作業是一件很好的事情,
那么,我們如何使用Golang來并發地進行多個http呼叫呢?如果你使用過C#或現代JavaScript,你可能使用過async/await來進行多個api呼叫,Golang并不那么容易,但這都是以效率為名義的,Go總是至少有一個goroutine在運行,它負責運行main(),我們可以在函式呼叫前用關鍵字go催生新的例程,如果你從事過Java/C#的異步呼叫,那么goroutine可能會讓你想起背景關系的概念,[文章來源:janrs.com] Go Scheduler允許開發者制作成千上萬個這種輕量級的goroutines,并為我們管理每個goroutines所花費的CPU時間,每當一個以go為前綴的函式被執行時,就會創建一個新的goroutine來運行該函式,主goroutine在生成一個新的goroutine后立即繼續前進,直到它遇到一個阻塞運算子(類似于C#或Js中的await),
原始呼叫
讓我們從一個簡單的控制臺應用開始,它呼叫了幾個GitHub組態檔,并檢查連接是否成功,起初,這里沒有goroutines,所有的呼叫都是連續進行的,效率不高,
// Auth: janrs.com
package main
import "fmt"
import "net/http"
func main() {
links := []string{
"https://github.com/fabpot",
"https://github.com/andrew",
"https://github.com/taylorotwell",
"https://github.com/egoist",
"https://github.com/HugoGiraudel",
}
checkUrls(links)
}
func checkUrls(urls []string) {
for _, link := range urls {
checkUrl(link)
}
}
func checkUrl(url string) {
_, err := http.Get(url)
if err != nil {
fmt.Println("We could not reach:", url)
} else {
fmt.Println("Success reaching the website:", url)
}
}
高性能呼叫
首先,我們需要添加一個叫做通道的東西,由于在自己的goroutine中運行的Golang函式只是簡單的函式,我們需要一種方法,通過它內部的goroutine可以把它們的結果告訴外部的goroutine;這就是使用通道來實作的,我們通過以下方式初始化它們: c := make(chan string) 我們能夠使用<- 箭頭將結果值發送到我們的通道,我們也可以使用這個箭頭將通道的值分配出去,
第二,我們需要添加一個跟蹤器,來跟蹤我們應該期待多少個值從這個通道出來,這可以通過使用sync.WaitGroup.WaitGroup的型別來完成,
落實這兩個想法,代碼如下,
import (
"fmt"
"net/http"
"sync"
)
func main() {
links := []string{
"https://github.com/fabpot",
"https://github.com/andrew",
"https://github.com/taylorotwell",
"https://github.com/egoist",
"https://github.com/HugoGiraudel",
}
checkUrls(links)
}
func checkUrls(urls []string) {
c := make(chan string)
var wg sync.WaitGroup
for _, link := range urls {
wg.Add(1) // 這告訴wg,現在這里有一個待處理的操作,
go checkUrl(link, c, &wg)
}
go func() {
wg.Wait() // 這將阻止Goroutine,直到WaitGroup計數器為零,#janrs.com
close(c) // 通道需要被關閉,否則下面的回圈將永遠持續下去
}()
// 這個簡略的回圈是一個無休止的回圈的語法糖,它只是在等待結果通過'c'通道進入,
for msg := range c {
fmt.Println(msg)
}
}
func checkUrl(url string, c chan string, wg *sync.WaitGroup) {
defer (*wg).Done()
_, err := http.Get(url)
if err != nil {
c <- "#janrs.com#We could not reach:" + url // 將結果輸入通道
} else {
c <- "Success reaching the website:" + url // 將結果輸入通道
}
}
轉載請注明來源:https://janrs.com/2023/03/用goroutines同時進行多個api呼叫/
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/545551.html
標籤:其他
上一篇:openfoam 智能指標探索
