欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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)文章

  • golang生成RSA公鑰和密鑰的實(shí)現(xiàn)方法

    golang生成RSA公鑰和密鑰的實(shí)現(xiàn)方法

    本文主要介紹了golang生成RSA公鑰和密鑰的實(shí)現(xiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2024-08-08
  • go語(yǔ)言實(shí)現(xiàn)Elasticsearches批量修改查詢及發(fā)送MQ操作示例

    go語(yǔ)言實(shí)現(xiàn)Elasticsearches批量修改查詢及發(fā)送MQ操作示例

    這篇文章主要為大家介紹了go語(yǔ)言實(shí)現(xiàn)Elasticsearches批量修改查詢及發(fā)送MQ操作示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-04-04
  • 一文總結(jié)Go語(yǔ)言切片核心知識(shí)點(diǎn)和坑

    一文總結(jié)Go語(yǔ)言切片核心知識(shí)點(diǎn)和坑

    都說(shuō)Go的切片用起來(lái)絲滑得很,Java中的List怎么用,切片就怎么用,作為曾經(jīng)的Java選手,因?yàn)榍衅氖褂貌坏卯?dāng),喜提缺陷若干,本文就給大家總結(jié)一下Go語(yǔ)言切片核心知識(shí)點(diǎn)和坑,需要的朋友可以參考下
    2023-06-06
  • go語(yǔ)言題解LeetCode1122數(shù)組的相對(duì)排序

    go語(yǔ)言題解LeetCode1122數(shù)組的相對(duì)排序

    這篇文章主要為大家介紹了go語(yǔ)言題解LeetCode1122數(shù)組的相對(duì)排序,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12
  • 一文帶你了解Go中跟蹤函數(shù)調(diào)用鏈的實(shí)現(xiàn)

    一文帶你了解Go中跟蹤函數(shù)調(diào)用鏈的實(shí)現(xiàn)

    這篇文章主要為大家詳細(xì)介紹了go如何實(shí)現(xiàn)一個(gè)自動(dòng)注入跟蹤代碼,并輸出有層次感的函數(shù)調(diào)用鏈跟蹤命令行工具,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-11-11
  • 使用go實(shí)現(xiàn)常見(jiàn)的數(shù)據(jù)結(jié)構(gòu)

    使用go實(shí)現(xiàn)常見(jiàn)的數(shù)據(jù)結(jié)構(gòu)

    這篇文章主要介紹了使用go實(shí)現(xiàn)常見(jiàn)的數(shù)據(jù)結(jié)構(gòu),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-03-03
  • vscode上搭建go開(kāi)發(fā)環(huán)境詳細(xì)完整過(guò)程

    vscode上搭建go開(kāi)發(fā)環(huán)境詳細(xì)完整過(guò)程

    這篇文章主要給大家介紹了關(guān)于vscode上搭建go開(kāi)發(fā)環(huán)境的詳細(xì)完整過(guò)程,Go語(yǔ)言或?qū)⒊蔀樾碌闹髁﹂_(kāi)發(fā)語(yǔ)言,Go是google開(kāi)發(fā)的一種靜態(tài)強(qiáng)類型、編譯型、并發(fā)型,并具有垃圾回收功能的編程語(yǔ)言,所以我們有必要學(xué)習(xí)并掌握它,需要的朋友可以參考下
    2023-10-10
  • 詳解golang中接口使用的最佳時(shí)機(jī)

    詳解golang中接口使用的最佳時(shí)機(jī)

    接口在系統(tǒng)設(shè)計(jì)中,以及代碼重構(gòu)優(yōu)化中,是一個(gè)不可或缺的工具,能夠幫助我們寫出可擴(kuò)展,可維護(hù)性更強(qiáng)的程序,本文主要為大家介紹一下golang中接口使用的最佳時(shí)機(jī),有興趣的可以了解下
    2023-09-09
  • golang實(shí)現(xiàn)通過(guò)smtp發(fā)送電子郵件的方法

    golang實(shí)現(xiàn)通過(guò)smtp發(fā)送電子郵件的方法

    這篇文章主要介紹了golang實(shí)現(xiàn)通過(guò)smtp發(fā)送電子郵件的方法,實(shí)例分析了Go語(yǔ)言基于SMTP協(xié)議發(fā)送郵件的相關(guān)技巧,需要的朋友可以參考下
    2016-07-07
  • 如何使用go實(shí)現(xiàn)創(chuàng)建WebSocket服務(wù)器

    如何使用go實(shí)現(xiàn)創(chuàng)建WebSocket服務(wù)器

    文章介紹了如何使用Go語(yǔ)言和gorilla/websocket庫(kù)創(chuàng)建一個(gè)簡(jiǎn)單的WebSocket服務(wù)器,并實(shí)現(xiàn)商品信息的實(shí)時(shí)廣播,感興趣的朋友一起看看吧
    2024-11-11

最新評(píng)論