最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Go高級(jí)特性之并發(fā)處理http詳解

 更新時(shí)間:2024年02月19日 11:17:23   作者:Goland貓  
Golang?作為一種高效的編程語(yǔ)言,提供了多種方法來(lái)實(shí)現(xiàn)并發(fā)發(fā)送?HTTP?請(qǐng)求,本文將深入探討?Golang?中并發(fā)發(fā)送?HTTP?請(qǐng)求的最佳技術(shù)和實(shí)踐,希望對(duì)大家有所幫助

引言

在當(dāng)今高度互聯(lián)的世界中,Web 應(yīng)用程序的性能和響應(yīng)能力變得至關(guān)重要。大多數(shù) Web 應(yīng)用程序需要與多個(gè)外部服務(wù)進(jìn)行通信,例如數(shù)據(jù)庫(kù)、API、第三方服務(wù)等。并發(fā)發(fā)送 HTTP 請(qǐng)求是提高應(yīng)用程序性能并保持響應(yīng)能力的關(guān)鍵。Golang 作為一種高效的編程語(yǔ)言,提供了多種方法來(lái)實(shí)現(xiàn)并發(fā)發(fā)送 HTTP 請(qǐng)求。本文將深入探討 Golang 中并發(fā)發(fā)送 HTTP 請(qǐng)求的最佳技術(shù)和實(shí)踐。

使用 Goroutines 的基本方法

當(dāng)談到在 Golang 中實(shí)現(xiàn)并發(fā)時(shí),最直接的方法是使用 routine。這些是 Go 中并發(fā)的構(gòu)建塊,提供了一種簡(jiǎn)單而強(qiáng)大的并發(fā)執(zhí)行函數(shù)的方法。

Goroutine 入門

要啟動(dòng)一個(gè) routine,只需在函數(shù)調(diào)用前加上``關(guān)鍵字即可。這會(huì)將函數(shù)作為 routine 啟動(dòng),從而允許主程序繼續(xù)獨(dú)立運(yùn)行。這就像開(kāi)始一項(xiàng)任務(wù)并繼續(xù)前進(jìn)而不等待它完成。

例如,考慮發(fā)送 HTTP 請(qǐng)求的場(chǎng)景。通常,你會(huì)調(diào)用類似 的函數(shù)sendRequest(),并且你的程序?qū)⒌却摵瘮?shù)完成。使用 routine,你可以同時(shí)執(zhí)行此操作:

package main

import (
	"fmt"
	"net/http"
)

func main() {
	urls := []string{"http://example.com", "http://example.org"}

	for _, url := range urls {
		go func(url string) {
			resp, err := http.Get(url)
			if err != nil {
				fmt.Println("Error:", err)
				return
			}

			defer resp.Body.Close()

			// 處理響應(yīng)內(nèi)容或其他邏輯
		}(url)
	}

	// 等待所有請(qǐng)求完成
	// ...
}

這個(gè)循環(huán)為每個(gè) URL 啟動(dòng)一個(gè)新的 routine,大大減少了程序發(fā)送所有請(qǐng)求所需的時(shí)間。通過(guò)創(chuàng)建多個(gè) goroutine,每個(gè) goroutine 發(fā)送一個(gè) HTTP 請(qǐng)求,我們可以實(shí)現(xiàn)并發(fā)地發(fā)送多個(gè)請(qǐng)求。

并發(fā) HTTP 請(qǐng)求的方法

由于沒(méi)有限制 goroutine 數(shù)量,如果我們把全部任務(wù)都放到并發(fā) Goroutine 中去執(zhí)行,雖然效率比較高。但當(dāng)不加控制的 goroutine 瘋狂創(chuàng)建時(shí)候,服務(wù)器系統(tǒng)資源使用率飆升宕機(jī),直到進(jìn)程被自動(dòng) kill 不然無(wú)法提供任何其它服務(wù)。

上面的案例是我們不加控制 goroutine 數(shù)量限制從而導(dǎo)致宕機(jī)的,因此只要我們控制了 goroutine 數(shù)量就能避免這種問(wèn)題!

WaitGroup

要確保所有并發(fā)請(qǐng)求完成后再繼續(xù)執(zhí)行后續(xù)操作,可以使用 sync.WaitGroup。sync 包提供的 WaitGroup 類型可以幫助我們等待一組并發(fā)操作的完成。

package main

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

func main() {
	urls := []string{"http://example.com", "http://example.org"}

	var wg sync.WaitGroup

	for _, url := range urls {
		wg.Add(1)
		go func(url string) {
			defer wg.Done()

			resp, err := http.Get(url)
			if err != nil {
				fmt.Println("Error:", err)
				return
			}

			defer resp.Body.Close()

			// 處理響應(yīng)內(nèi)容或其他邏輯
		}(url)
	}

	wg.Wait() // 等待所有請(qǐng)求完成
	// ...
}

通過(guò)調(diào)用 sync.WaitGroup 的 Wait() 方法,我們可以確保所有的 goroutine 執(zhí)行完成后再繼續(xù)執(zhí)行后續(xù)操作。

Channels

我們可以使用Channels來(lái)控制并發(fā)請(qǐng)求數(shù)量。通過(guò)創(chuàng)建一個(gè)有容量限制的通道,可以實(shí)現(xiàn)對(duì)并發(fā)請(qǐng)求數(shù)量的有效控制

package main

import (
	"fmt"
	"net/http"
)

func main() {
	urls := []string{"http://example.com", "http://example.org"}
	concurrency := 5
	sem := make(chan bool, concurrency)

	for _, url := range urls {
		sem <- true // 發(fā)送信號(hào)控制并發(fā)數(shù)量
		go func(url string) {
			defer func() { <-sem }() // 釋放信號(hào)

			resp, err := http.Get(url)
			if err != nil {
				fmt.Println("Error:", err)
				return
			}

			defer resp.Body.Close()

			// 處理響應(yīng)內(nèi)容或其他邏輯
		}(url)
	}

	// 等待所有請(qǐng)求完成
	// ...
}

通過(guò)設(shè)置通道的容量為并發(fā)數(shù)量,我們可以確保同時(shí)發(fā)送的請(qǐng)求數(shù)量不超過(guò)設(shè)定的限制。這種方法對(duì)于控制并發(fā)請(qǐng)求數(shù)量非常有效。

Worker Pools

Worker Pools 是一種常見(jiàn)的并發(fā)模式,它可以有效地控制并發(fā)發(fā)送 HTTP 請(qǐng)求的數(shù)量。通過(guò)創(chuàng)建一組固定數(shù)量的 worker goroutines,并將請(qǐng)求任務(wù)分配給它們來(lái)處理,我們可以控制并發(fā)請(qǐng)求數(shù)量,減輕資源競(jìng)爭(zhēng)和過(guò)載的壓力。

package main

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

type Worker struct {
	ID        int
	Request   chan string
	Responses chan string
}

func NewWorker(id int) *Worker {
	return &Worker{
		ID:        id,
		Request:   make(chan string),
		Responses: make(chan string),
	}
}

func (w *Worker) Start(wg *sync.WaitGroup) {
	go func() {
		defer wg.Done()

		for url := range w.Request {
			resp, err := http.Get(url)
			if err != nil {
				w.Responses <- fmt.Sprintf("Error: %s", err)
				continue
			}

			defer resp.Body.Close()

			// 處理響應(yīng)內(nèi)容或其他邏輯
			w.Responses <- fmt.Sprintf("Worker %d: %s", w.ID, "Response")
		}
	}()
}

func main() {
	urls := []string{"http://example.com", "http://example.org"}
	concurrency := 5

	var wg sync.WaitGroup
	wg.Add(concurrency)

	workers := make([]*Worker, concurrency)
	for i := 0; i < concurrency; i++ {
		workers[i] = NewWorker(i)
		workers[i].Start(&wg)
	}

	go func() {
		for _, url := range urls {
			for _, worker := range workers {
				worker.Request <- url
			}
		}

		for _, worker := range workers {
			close(worker.Request)
		}
	}()

	for _, worker := range workers {
		for response := range worker.Responses {
			fmt.Println(response)
		}
	}

	wg.Wait()
}

通過(guò)使用 Worker Pools,我們可以控制并發(fā)請(qǐng)求數(shù)量,并發(fā)請(qǐng)求的數(shù)量不超過(guò) Worker Pools 中的 worker 數(shù)量。

更深入學(xué)習(xí)請(qǐng)查看探究 Go 的高級(jí)特性之 【處理1分鐘百萬(wàn)請(qǐng)求】

使用信號(hào)量限制 Goroutines

sync/semaphore 包提供了一種干凈有效的方法來(lái)限制并發(fā)運(yùn)行的 routine 數(shù)量。當(dāng)你想要更系統(tǒng)地管理資源分配時(shí),此方法特別有用。

package main

import (
	"context"
	"fmt"
	"golang.org/x/sync/semaphore"
	"net/http"
)

func main() {
	// 創(chuàng)建請(qǐng)求者并加載配置
	requester := http.DefaultClient

	// 定義要處理的 URL 列表
	urls := []string{"http://example.com", "http://example.org", "http://example.net"}

	maxConcurrency := int64(2) // 設(shè)置最大并發(fā)請(qǐng)求數(shù)量

	// 創(chuàng)建一個(gè)帶權(quán)重的信號(hào)量
	sem := semaphore.NewWeighted(maxConcurrency)

	ctx := context.Background()

	// 遍歷 URL 列表
	for _, url := range urls {
		// 在啟動(dòng) goroutine 前獲取信號(hào)量權(quán)重
		if err := sem.Acquire(ctx, 1); err != nil {
			fmt.Printf("無(wú)法獲取信號(hào)量:%v\n", err)
			continue
		}

		go func(url string) {
			defer sem.Release(1) // 在完成時(shí)釋放信號(hào)量權(quán)重

			// 使用請(qǐng)求者獲取 URL 對(duì)應(yīng)的響應(yīng)
			res, err := requester.Get(url)
			if err != nil {
				fmt.Printf("請(qǐng)求失?。?v\n", err)
				return
			}
			defer res.Body.Close()

			fmt.Printf("%s: %d\n", url, res.StatusCode)
		}(url)
	}

	// 等待所有 goroutine 釋放它們的信號(hào)量權(quán)重
	if err := sem.Acquire(ctx, maxConcurrency); err != nil {
		fmt.Printf("等待時(shí)無(wú)法獲取信號(hào)量:%v\n", err)
	}
}

那么,最好的方法是什么

在探索了 Go 中處理并發(fā) HTTP 請(qǐng)求的各種方法之后,問(wèn)題出現(xiàn)了:最好的方法是什么?正如軟件工程中經(jīng)常出現(xiàn)的情況一樣,答案取決于應(yīng)用程序的具體要求和約束。讓我們考慮確定最合適方法的關(guān)鍵因素:

評(píng)估你的需求

  • 請(qǐng)求規(guī)模:如果你正在處理大量請(qǐng)求,工作池或基于信號(hào)量的方法可以更好地控制資源使用。
  • 錯(cuò)誤處理:如果強(qiáng)大的錯(cuò)誤處理至關(guān)重要,那么使用通道或信號(hào)量包可以提供更結(jié)構(gòu)化的錯(cuò)誤管理。
  • 速率限制:對(duì)于需要遵守速率限制的應(yīng)用程序,使用通道或信號(hào)量包限制 routine 可能是有效的。
  • 復(fù)雜性和可維護(hù)性:考慮每種方法的復(fù)雜性。雖然渠道提供了更多控制,但它們也增加了復(fù)雜性。另一方面,信號(hào)量包提供了更直接的解決方案。

錯(cuò)誤處理

由于 Go 中并發(fā)執(zhí)行的性質(zhì),routines 中的錯(cuò)誤處理是一個(gè)棘手的話題。由于 routine 獨(dú)立運(yùn)行,管理和傳播錯(cuò)誤可能具有挑戰(zhàn)性,但對(duì)于構(gòu)建健壯的應(yīng)用程序至關(guān)重要。以下是一些有效處理并發(fā) Go 程序中錯(cuò)誤的策略:

集中誤差通道

一種常見(jiàn)的方法是使用集中式錯(cuò)誤通道,所有 routine 都可以通過(guò)該通道發(fā)送錯(cuò)誤。然后,主 routine 可以監(jiān)聽(tīng)該通道并采取適當(dāng)?shù)牟僮鳌?/p>

func worker(errChan chan<- error) {
    // 執(zhí)行任務(wù)
    if err := doTask(); err != nil {
        errChan <- err // 將任何錯(cuò)誤發(fā)送到錯(cuò)誤通道
    }
}
func main() {
    errChan := make(chan error, 1) // 用于存儲(chǔ)錯(cuò)誤的緩沖通道
    go worker(errChan)
    if err := <-errChan; err != nil {
        // 處理錯(cuò)誤
        log.Printf("發(fā)生錯(cuò)誤:%v", err)
    }
}

或者你可以在不同的 routine 中監(jiān)聽(tīng) errChan。

func worker(errChan chan<- error, job Job) {
 // 執(zhí)行任務(wù)
 if err := doTask(job); err != nil {
  errChan <- err // 將任何錯(cuò)誤發(fā)送到錯(cuò)誤通道
 }
}
func listenErrors(done chan struct{}, errChan <-chan error) {
 for {
  select {
  case err := <-errChan:
   // 處理錯(cuò)誤
  case <-done:
   return
  }
 }
}
func main() {
 errChan := make(chan error, 1000) // 存儲(chǔ)錯(cuò)誤的通道
 done := make(chan struct{})       // 用于通知 goroutine 停止的通道
 go listenErrors(done, errChan)
 
 for _, job := range jobs {
   go worker(errChan, job)
 }
 // 等待所有 goroutine 完成(具體方式需要根據(jù)代碼的實(shí)際情況進(jìn)行實(shí)現(xiàn))
 done <- struct{}{} // 通知 goroutine 停止監(jiān)聽(tīng)錯(cuò)誤
}

Error Group

lang.org/x/sync/errgroup 包提供了一種便捷的方法來(lái)對(duì)多個(gè) routine 進(jìn)行分組并處理它們產(chǎn)生的任何錯(cuò)誤。errgroup.Group確保一旦任何 routine 發(fā)生錯(cuò)誤,所有后續(xù)操作都將被取消。

import "golang.org/x/sync/errgroup"
func main() {
    g, ctx := errgroup.WithContext(context.Background())
    urls := []string{"http://example.com", "http://example.org"}
    for _, url := range urls {
        // 為每個(gè) URL 啟動(dòng)一個(gè) goroutine
        g.Go(func() error {
            // 替換為實(shí)際的 HTTP 請(qǐng)求邏輯
            _, err := fetchURL(ctx, url)
            return err
        })
    }
    // 等待所有請(qǐng)求完成
    if err := g.Wait(); err != nil {
        log.Printf("發(fā)生錯(cuò)誤:%v", err)
    }
}

這種方法簡(jiǎn)化了錯(cuò)誤處理,特別是在處理大量 routine 時(shí)。

以上就是Go高級(jí)特性之并發(fā)處理http詳解的詳細(xì)內(nèi)容,更多關(guān)于Go并發(fā)處理http的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 使用Go語(yǔ)言實(shí)現(xiàn)一個(gè)簡(jiǎn)單的詞頻分析系統(tǒng)

    使用Go語(yǔ)言實(shí)現(xiàn)一個(gè)簡(jiǎn)單的詞頻分析系統(tǒng)

    在數(shù)據(jù)分析和文本挖掘中,詞頻統(tǒng)計(jì)(Word Frequency Analysis) 是最基礎(chǔ)也是最常用的技術(shù)之一,本文將帶你用 Go 語(yǔ)言實(shí)現(xiàn)一個(gè)簡(jiǎn)易的 詞頻分析系統(tǒng),感興趣的小伙伴可以了解下
    2025-09-09
  • 詳解Golang語(yǔ)言HTTP客戶端實(shí)踐

    詳解Golang語(yǔ)言HTTP客戶端實(shí)踐

    本文主要介紹了Golang語(yǔ)言HTTP客戶端實(shí)踐,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • 最新評(píng)論

    海宁市| 宕昌县| 昌吉市| 方山县| 石柱| 老河口市| 若尔盖县| 沙洋县| 景德镇市| 香港 | 黄骅市| 南雄市| 贵阳市| 兴安县| 安溪县| 海宁市| 方正县| 米泉市| 郁南县| 福鼎市| 寿阳县| 邯郸市| 临洮县| 合江县| 左贡县| 徐汇区| 扎囊县| 厦门市| 阳高县| 皋兰县| 盐边县| 泌阳县| 辽宁省| 灌南县| 隆子县| 曲阳县| 横山县| 唐河县| 东海县| 汝南县| 石泉县|