首頁 > 軟體

GoRoutines高效能同時進行多個Api呼叫實現

2023-03-05 14:00:55

正文

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    // 將結果輸入通道
	}
}

以上就是GoRoutines高效能同時進行多個Api呼叫實現的詳細內容,更多關於GoRoutines多個Api同時呼叫的資料請關注it145.com其它相關文章!


IT145.com E-mail:sddin#qq.com