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

Go語(yǔ)言實(shí)現(xiàn)多協(xié)程并發(fā)下載網(wǎng)頁(yè)內(nèi)容的完整代碼

 更新時(shí)間:2025年08月04日 08:27:30   作者:程序員愛釣魚  
在互聯(lián)網(wǎng)項(xiàng)目中,我們常需要批量獲取多個(gè)網(wǎng)頁(yè)的內(nèi)容,如果逐個(gè)請(qǐng)求(串行),效率將非常低下,Go天生支持高并發(fā),所以本文實(shí)戰(zhàn)演示如何使用Goroutine和Channel,實(shí)現(xiàn)多協(xié)程并發(fā)抓取網(wǎng)頁(yè)內(nèi)容,提升網(wǎng)絡(luò)請(qǐng)求效率,為構(gòu)建爬蟲、內(nèi)容聚合器、API 批量采集器打下基礎(chǔ)

一、實(shí)戰(zhàn)背景

在互聯(lián)網(wǎng)項(xiàng)目中,我們常需要批量獲取多個(gè)網(wǎng)頁(yè)的內(nèi)容,例如:

  • 爬蟲程序抓取網(wǎng)頁(yè) HTML
  • 數(shù)據(jù)聚合服務(wù)請(qǐng)求多個(gè) API
  • 批量檢測(cè)多個(gè) URL 的可用性

如果逐個(gè)請(qǐng)求(串行),效率將非常低下。Go 天生支持高并發(fā),我們可以用 Goroutine 實(shí)現(xiàn) 多協(xié)程并發(fā)下載網(wǎng)頁(yè)內(nèi)容,顯著提高吞吐能力。

二、實(shí)戰(zhàn)目標(biāo)

我們將構(gòu)建一個(gè)小型并發(fā)網(wǎng)頁(yè)下載器,具備以下能力:

  1. 輸入一組網(wǎng)址列表
  2. 使用 Goroutine 并發(fā)請(qǐng)求多個(gè)網(wǎng)頁(yè)
  3. 使用 Channel 收集下載結(jié)果
  4. 打印成功/失敗狀態(tài)與網(wǎng)頁(yè)內(nèi)容摘要
  5. 支持 WaitGroup 等待所有任務(wù)完成

三、完整代碼實(shí)現(xiàn)

package main

import (
    "fmt"
    "io"
    "net/http"
    "strings"
    "sync"
    "time"
)

type Result struct {
    URL    string
    Status string
    Length int
    Error  error
}

// 下載網(wǎng)頁(yè)內(nèi)容并寫入結(jié)果通道
func fetchURL(url string, wg *sync.WaitGroup, resultCh chan<- Result) {
    defer wg.Done()

    client := http.Client{
        Timeout: 5 * time.Second,
    }

    resp, err := client.Get(url)
    if err != nil {
        resultCh <- Result{URL: url, Status: "請(qǐng)求失敗", Error: err}
        return
    }
    defer resp.Body.Close()

    body, err := io.ReadAll(resp.Body)
    if err != nil {
        resultCh <- Result{URL: url, Status: "讀取失敗", Error: err}
        return
    }

    resultCh <- Result{
        URL:    url,
        Status: resp.Status,
        Length: len(body),
    }
}

func main() {
    urls := []string{
        "https://example.com",
        "https://httpbin.org/get",
        "https://golang.org",
        "https://nonexistent.example.com", // 故意的錯(cuò)誤URL
    }

    var wg sync.WaitGroup
    resultCh := make(chan Result, len(urls))

    // 啟動(dòng)多個(gè)下載協(xié)程
    for _, url := range urls {
        wg.Add(1)
        go fetchURL(url, &wg, resultCh)
    }

    // 等待所有任務(wù)完成后關(guān)閉通道
    go func() {
        wg.Wait()
        close(resultCh)
    }()

    // 讀取結(jié)果
    for res := range resultCh {
        if res.Error != nil {
            fmt.Printf("[失敗] %s:%v\n", res.URL, res.Error)
        } else {
            snippet := fmt.Sprintf("%d 字節(jié)", res.Length)
            if res.Length > 0 {
                snippet = fmt.Sprintf("%s 內(nèi)容預(yù)覽:%s", snippet, strings.TrimSpace(string([]byte(res.URL)[:min(50, res.Length)])))
            }
            fmt.Printf("[成功] %s:%s\n", res.URL, snippet)
        }
    }

    fmt.Println("所有網(wǎng)頁(yè)請(qǐng)求已完成。")
}

func min(a, b int) int {
    if a < b {
        return a
    }
    return b
}

四、輸出示例

[成功] https://example.com:1256 字節(jié) 內(nèi)容預(yù)覽:https://example.com
[成功] https://httpbin.org/get:349 字節(jié) 內(nèi)容預(yù)覽:https://httpbin.org/get
[成功] https://golang.org:3578 字節(jié) 內(nèi)容預(yù)覽:https://golang.org
[失敗] https://nonexistent.example.com:Get "https://nonexistent.example.com": dial tcp: ...
所有網(wǎng)頁(yè)請(qǐng)求已完成。

五、重點(diǎn)知識(shí)點(diǎn)講解

1. 使用 Goroutine 啟動(dòng)并發(fā)請(qǐng)求

go fetchURL(url, &wg, resultCh)

每個(gè)網(wǎng)頁(yè)請(qǐng)求都是一個(gè)輕量級(jí)的線程(協(xié)程),同時(shí)運(yùn)行,最大化資源利用。

2. 使用 sync.WaitGroup 等待所有任務(wù)完成

WaitGroup 是 Goroutine 的最佳搭檔,確保主線程不會(huì)提前退出。

wg.Add(1)
defer wg.Done()

3. 使用帶緩沖的 Channel 收集結(jié)果

resultCh := make(chan Result, len(urls))

避免協(xié)程阻塞,收集所有結(jié)果后統(tǒng)一處理。

4. 設(shè)置請(qǐng)求超時(shí)

使用 http.Client{ Timeout: ... } 可防止因某個(gè) URL 卡住導(dǎo)致整體阻塞。

5. 防止通道未關(guān)閉阻塞

一定要在所有任務(wù)完成后關(guān)閉結(jié)果通道:

go func() {
    wg.Wait()
    close(resultCh)
}()

六、可擴(kuò)展方向

這個(gè)簡(jiǎn)單的并發(fā)網(wǎng)頁(yè)下載器可以繼續(xù)擴(kuò)展為:

功能方向實(shí)現(xiàn)建議
限制最大并發(fā)數(shù)使用帶緩沖的 chan struct{} 控制令牌
下載網(wǎng)頁(yè)保存文件使用 os.Create 寫入 HTML 文件
支持重試機(jī)制封裝帶重試的請(qǐng)求邏輯
使用 context 控制取消或超時(shí)實(shí)現(xiàn)更復(fù)雜的任務(wù)調(diào)度系統(tǒng)
支持代理設(shè)置 Transport.Proxy 實(shí)現(xiàn)

七、小結(jié)

通過(guò)本篇案例你掌握了:

  • 使用 Goroutine 啟動(dòng)并發(fā)任務(wù)
  • 使用 Channel 匯總?cè)蝿?wù)結(jié)果
  • 使用 WaitGroup 管理協(xié)程生命周期
  • 網(wǎng)絡(luò)請(qǐng)求的錯(cuò)誤處理與超時(shí)機(jī)制

這為你實(shí)現(xiàn)一個(gè)功能完善的高并發(fā)爬蟲、網(wǎng)頁(yè)檢測(cè)器或 API 批量處理工具奠定了基礎(chǔ)。

以上就是Go語(yǔ)言實(shí)現(xiàn)多協(xié)程并發(fā)下載網(wǎng)頁(yè)內(nèi)容的完整代碼的詳細(xì)內(nèi)容,更多關(guān)于Go多協(xié)程并發(fā)下載網(wǎng)頁(yè)內(nèi)容的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Golang WebView跨平臺(tái)的桌面應(yīng)用庫(kù)的使用

    Golang WebView跨平臺(tái)的桌面應(yīng)用庫(kù)的使用

    Golang WebView是一個(gè)強(qiáng)大的桌面應(yīng)用庫(kù),本文介紹了Golang WebView的特點(diǎn)和使用方法,并列舉示例詳細(xì)的介紹了其在實(shí)際項(xiàng)目中的應(yīng)用,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-03-03
  • go中控制goroutine數(shù)量的方法

    go中控制goroutine數(shù)量的方法

    這篇文章主要介紹了go中控制goroutine數(shù)量的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-05-05
  • go語(yǔ)言中的json與map相互轉(zhuǎn)換實(shí)現(xiàn)

    go語(yǔ)言中的json與map相互轉(zhuǎn)換實(shí)現(xiàn)

    本文主要介紹了go語(yǔ)言中的json與map相互轉(zhuǎn)換實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-08-08
  • Go語(yǔ)言對(duì)JSON進(jìn)行編碼和解碼的方法

    Go語(yǔ)言對(duì)JSON進(jìn)行編碼和解碼的方法

    這篇文章主要介紹了Go語(yǔ)言對(duì)JSON進(jìn)行編碼和解碼的方法,涉及Go語(yǔ)言操作json的技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-02-02
  • golang panic 函數(shù)用法示例詳解

    golang panic 函數(shù)用法示例詳解

    在Go語(yǔ)言中,panic用于觸發(fā)不可恢復(fù)的錯(cuò)誤,終止函數(shù)執(zhí)行并逐層向上觸發(fā)defer,最終若未被recover捕獲,程序會(huì)崩潰,recover用于在defer函數(shù)中捕獲panic,恢復(fù)程序流程,建議優(yōu)先返回error,僅在嚴(yán)重錯(cuò)誤或不可恢復(fù)場(chǎng)景下使用panic,并在關(guān)鍵位置recover,感興趣的朋友一起看看吧
    2025-03-03
  • go中Excelize處理excel表實(shí)現(xiàn)帶數(shù)據(jù)校驗(yàn)的文件導(dǎo)出

    go中Excelize處理excel表實(shí)現(xiàn)帶數(shù)據(jù)校驗(yàn)的文件導(dǎo)出

    本文主要介紹了go中Excelize處理excel表實(shí)現(xiàn)帶數(shù)據(jù)校驗(yàn)的文件導(dǎo)出,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-06-06
  • Go使用Redis實(shí)現(xiàn)分布式鎖的常見方法

    Go使用Redis實(shí)現(xiàn)分布式鎖的常見方法

    Redis?提供了一些原語(yǔ),可以幫助我們實(shí)現(xiàn)高效的分布式鎖,下邊是使用?Redis?實(shí)現(xiàn)分布式鎖的一種常見方法,通過(guò)代碼示例給大家介紹的非常詳細(xì),具有一定的參考價(jià)值,需要的朋友可以參考下
    2024-11-11
  • 解決vscode中g(shù)olang插件依賴安裝失敗問(wèn)題

    解決vscode中g(shù)olang插件依賴安裝失敗問(wèn)題

    這篇文章主要介紹了解決vscode中g(shù)olang插件依賴安裝失敗問(wèn)題,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2019-08-08
  • go的defer和閉包示例說(shuō)明(非內(nèi)部實(shí)現(xiàn))

    go的defer和閉包示例說(shuō)明(非內(nèi)部實(shí)現(xiàn))

    這篇文章主要為大家介紹了go的defer和閉包示例說(shuō)明(非內(nèi)部實(shí)現(xiàn)),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-08-08
  • 詳解Go語(yǔ)言如何使用xorm實(shí)現(xiàn)讀取mysql

    詳解Go語(yǔ)言如何使用xorm實(shí)現(xiàn)讀取mysql

    xorm是go語(yǔ)言的常用orm之一,可以用來(lái)操作數(shù)據(jù)庫(kù)。本文就來(lái)和大家聊聊Go語(yǔ)言如何使用xorm實(shí)現(xiàn)讀取mysql功能,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2022-11-11

最新評(píng)論