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

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

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

引言

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

使用 Goroutines 的基本方法

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

Goroutine 入門

要啟動一個 routine,只需在函數調用前加上``關鍵字即可。這會將函數作為 routine 啟動,從而允許主程序繼續(xù)獨立運行。這就像開始一項任務并繼續(xù)前進而不等待它完成。

例如,考慮發(fā)送 HTTP 請求的場景。通常,你會調用類似 的函數sendRequest(),并且你的程序將等待該函數完成。使用 routine,你可以同時執(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()

			// 處理響應內容或其他邏輯
		}(url)
	}

	// 等待所有請求完成
	// ...
}

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

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

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

上面的案例是我們不加控制 goroutine 數量限制從而導致宕機的,因此只要我們控制了 goroutine 數量就能避免這種問題!

WaitGroup

要確保所有并發(fā)請求完成后再繼續(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()

			// 處理響應內容或其他邏輯
		}(url)
	}

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

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

Channels

我們可以使用Channels來控制并發(fā)請求數量。通過創(chuàng)建一個有容量限制的通道,可以實現(xiàn)對并發(fā)請求數量的有效控制

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ā)送信號控制并發(fā)數量
		go func(url string) {
			defer func() { <-sem }() // 釋放信號

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

			defer resp.Body.Close()

			// 處理響應內容或其他邏輯
		}(url)
	}

	// 等待所有請求完成
	// ...
}

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

Worker Pools

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

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()

			// 處理響應內容或其他邏輯
			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()
}

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

更深入學習請查看探究 Go 的高級特性之 【處理1分鐘百萬請求】

使用信號量限制 Goroutines

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

package main

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

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

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

	maxConcurrency := int64(2) // 設置最大并發(fā)請求數量

	// 創(chuàng)建一個帶權重的信號量
	sem := semaphore.NewWeighted(maxConcurrency)

	ctx := context.Background()

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

		go func(url string) {
			defer sem.Release(1) // 在完成時釋放信號量權重

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

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

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

那么,最好的方法是什么

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

評估你的需求

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

錯誤處理

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

集中誤差通道

一種常見的方法是使用集中式錯誤通道,所有 routine 都可以通過該通道發(fā)送錯誤。然后,主 routine 可以監(jiān)聽該通道并采取適當的操作。

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

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

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

Error Group

lang.org/x/sync/errgroup 包提供了一種便捷的方法來對多個 routine 進行分組并處理它們產生的任何錯誤。errgroup.Group確保一旦任何 routine 發(fā)生錯誤,所有后續(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 {
        // 為每個 URL 啟動一個 goroutine
        g.Go(func() error {
            // 替換為實際的 HTTP 請求邏輯
            _, err := fetchURL(ctx, url)
            return err
        })
    }
    // 等待所有請求完成
    if err := g.Wait(); err != nil {
        log.Printf("發(fā)生錯誤:%v", err)
    }
}

這種方法簡化了錯誤處理,特別是在處理大量 routine 時。

以上就是Go高級特性之并發(fā)處理http詳解的詳細內容,更多關于Go并發(fā)處理http的資料請關注腳本之家其它相關文章!

相關文章

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

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

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

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

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

    一文總結Go語言切片核心知識點和坑

    都說Go的切片用起來絲滑得很,Java中的List怎么用,切片就怎么用,作為曾經的Java選手,因為切片的使用不得當,喜提缺陷若干,本文就給大家總結一下Go語言切片核心知識點和坑,需要的朋友可以參考下
    2023-06-06
  • go語言題解LeetCode1122數組的相對排序

    go語言題解LeetCode1122數組的相對排序

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

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

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

    使用go實現(xiàn)常見的數據結構

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

    vscode上搭建go開發(fā)環(huán)境詳細完整過程

    這篇文章主要給大家介紹了關于vscode上搭建go開發(fā)環(huán)境的詳細完整過程,Go語言或將成為新的主力開發(fā)語言,Go是google開發(fā)的一種靜態(tài)強類型、編譯型、并發(fā)型,并具有垃圾回收功能的編程語言,所以我們有必要學習并掌握它,需要的朋友可以參考下
    2023-10-10
  • 詳解golang中接口使用的最佳時機

    詳解golang中接口使用的最佳時機

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

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

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

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

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

最新評論