国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Go源碼實現(xiàn)使用多線程并發(fā)下載大文件的功能

這篇具有很好參考價值的文章主要介紹了Go源碼實現(xiàn)使用多線程并發(fā)下載大文件的功能。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

摘要:Go語言編碼實現(xiàn)了使用多線程并發(fā)下載文件的功能。

1. 代碼流程介紹

1. 獲取系統(tǒng)的CPU核心數(shù)量,并將其作為線程數(shù)的參考值,并打印出來。
2. 定義要下載的文件的URL、線程數(shù)和輸出文件名。
3. 使用`getFileSize()`函數(shù)獲取文件大小,并打印出來。
4. 根據(jù)文件大小和線程數(shù)計算文件塊大小,如果是最后一次線程的結(jié)尾設置為文件結(jié)尾,確保文件下載的完整性。
5. 創(chuàng)建一個等待組(`sync.WaitGroup`),用于確保所有下載完成后再合并文件。
6. 創(chuàng)建一個通道(`chunkPaths`),用于接收下載完成的文件塊路徑。
7. 啟動多個goroutine并發(fā)下載文件塊,每個goroutine負責下載指定范圍的文件塊。
8. 每個goroutine使用`downloadChunk()`函數(shù)下載文件塊,并將下載完成的文件塊路徑發(fā)送到通道。
9. 等待所有下載完成,然后關閉通道,表示所有文件塊都已下載完成。
10. 創(chuàng)建一個輸出文件。
11. 使用`mergeChunk()`函數(shù)將下載的文件塊合并到輸出文件中,并在合并過程中打印合并成功或失敗的信息。
12. 在合并完成后,刪除臨時的文件塊。
13. 打印文件下載完成的消息。

源碼通過并發(fā)下載文件塊,利用多線程來加快文件下載的速度。每個線程負責下載文件的一個部分,下載完成后將文件塊合并到最終的輸出文件中。通過合理設置線程數(shù),可以充分利用可用的CPU資源,提高下載效率。

請注意,代碼中使用了`http`和`os`包來進行文件下載和操作,需要保證網(wǎng)絡連接正常,并且有足夠的權限來創(chuàng)建和刪除文件。

2. Go完整源碼

package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
	"runtime"
	"sync"
)

const (
	fileURL = "http://example.com/large-file.zip" // 要下載的文件URL
	// threads    = 5                                                                                                // 并發(fā)下載的線程數(shù)
	outputFile = "output.zip" // 下載完成后的輸出文件名
)

func main() {

	// CPU數(shù)量作為線程數(shù)量
    numCPU := runtime.NumCPU()
	fmt.Println("CPU核心數(shù)量:", numCPU)
	threads := numCPU
	fmt.Println("多線程數(shù)量:", threads)
	fmt.Println("開始下載文件...")

	// 獲取文件大小
	fileSize, err := getFileSize(fileURL)
	if err != nil {
		fmt.Println("無法獲取文件大小:", err)
		return
	}
	fmt.Println("文件大小:", fileSize, "bytes")

	// 計算文件塊大小
	chunkSize := fileSize / int64(threads)

	// 創(chuàng)建等待組,確保所有下載完成后再合并文件
	var wg sync.WaitGroup
	wg.Add(threads)

	// 創(chuàng)建一個通道用于接收下載完成的文件塊路徑
	chunkPaths := make(chan string, threads)

	// 啟動多個 goroutine 并發(fā)下載文件塊
	for i := 0; i < threads; i++ {
		go func(index int) {
			defer wg.Done()

			start := int64(index) * chunkSize
			end := start + chunkSize - 1
			// 如果是最后一次線程的結(jié)尾設置為文件結(jié)尾,確保文件下載的完整性

			if index == threads-1 {
				end = fileSize - 1
			}

			fmt.Printf("線程 %d 開始下載:%d-%d\n", index, start, end)
			chunkPath, err := downloadChunk(fileURL, start, end)
			if err != nil {
				fmt.Printf("線程 %d 下載失?。?v\n", index, err)
			} else {
				fmt.Printf("線程 %d 下載完成:%d-%d\n", index, start, end)
				chunkPaths <- chunkPath // 將下載完成的文件塊路徑發(fā)送到通道
			}
		}(i)
	}

	// 等待所有下載完成
	wg.Wait()
	close(chunkPaths) // 關閉通道,表示所有文件塊都已下載完成

	// 創(chuàng)建一個輸出文件
	output, err := os.Create(outputFile)
	if err != nil {
		fmt.Println("無法創(chuàng)建輸出文件:", err)
		return
	}
	defer output.Close()

	// 合并下載的文件塊到輸出文件
	for chunkPath := range chunkPaths {
		fmt.Println("合并文件塊:", chunkPath)
		err := mergeChunk(chunkPath, output)
		if err != nil {
			fmt.Printf("合并文件塊失?。?v\n", err)
		} else {
			fmt.Printf("合并文件塊成功:%s\n", chunkPath)
		}

		// 刪除臨時文件塊
		err = os.Remove(chunkPath)
		if err != nil {
			fmt.Printf("刪除文件塊失?。?v\n", err)
		}
	}

	fmt.Println("文件下載完成。")
}

// 獲取文件大小
func getFileSize(url string) (int64, error) {
	resp, err := http.Head(url)
	if err != nil {
		return 0, err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		return 0, fmt.Errorf("服務器返回錯誤: %v", resp.Status)
	}

	return resp.ContentLength, nil
}

// 下載文件塊
func downloadChunk(url string, start, end int64) (string, error) {
	req, err := http.NewRequest("GET", url, nil)
	if err != nil {
		return "", err
	}
	req.Header.Set("Range", fmt.Sprintf("bytes=%d-%d", start, end))

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusPartialContent {
		return "", fmt.Errorf("服務器不支持分塊下載:%v", resp.Status)
	}

	// 創(chuàng)建一個臨時文件用于保存下載的文件塊
	chunkPath := fmt.Sprintf("chunk_%d_%d.tmp", start, end)
	chunkFile, err := os.Create(chunkPath)
	if err != nil {
		return "", err
	}
	defer chunkFile.Close()

	_, err = io.Copy(chunkFile, resp.Body)
	if err != nil {
		return "", err
	}

	return chunkPath, nil
}

// 合并文件塊
func mergeChunk(chunkPath string, output *os.File) error {
	chunkFile, err := os.Open(chunkPath)
	if err != nil {
		return err
	}
	defer chunkFile.Close()

	_, err = io.Copy(output, chunkFile)
	if err != nil {
		return err
	}

	return nil
}

3. 執(zhí)行結(jié)果

> go run .\largefile_download_goroutine.go
CPU核心數(shù)量: 8
多線程數(shù)量: 8
開始下載文件...
文件大小: 28057414 bytes
線程 7 開始下載:24550232-28057413
線程 1 開始下載:3507176-7014351
線程 0 開始下載:0-3507175
線程 4 開始下載:14028704-17535879
線程 3 開始下載:10521528-14028703
線程 5 開始下載:17535880-21043055
線程 6 開始下載:21043056-24550231
線程 2 開始下載:7014352-10521527
線程 0 下載完成:0-3507175
線程 7 下載完成:24550232-28057413
線程 3 下載完成:10521528-14028703
線程 1 下載完成:3507176-7014351
線程 2 下載完成:7014352-10521527
線程 4 下載完成:14028704-17535879
線程 6 下載完成:21043056-24550231
線程 5 下載完成:17535880-21043055
合并文件塊: chunk_0_3507175.tmp
合并文件塊成功:chunk_0_3507175.tmp
合并文件塊: chunk_24550232_28057413.tmp
合并文件塊成功:chunk_24550232_28057413.tmp
合并文件塊: chunk_10521528_14028703.tmp
合并文件塊成功:chunk_10521528_14028703.tmp
合并文件塊: chunk_3507176_7014351.tmp
合并文件塊成功:chunk_3507176_7014351.tmp
合并文件塊: chunk_7014352_10521527.tmp
合并文件塊成功:chunk_7014352_10521527.tmp
合并文件塊: chunk_14028704_17535879.tmp
合并文件塊成功:chunk_14028704_17535879.tmp
合并文件塊: chunk_21043056_24550231.tmp
合并文件塊成功:chunk_21043056_24550231.tmp
合并文件塊: chunk_17535880_21043055.tmp
合并文件塊成功:chunk_17535880_21043055.tmp
文件下載完成。文章來源地址http://www.zghlxwxcb.cn/news/detail-719888.html

到了這里,關于Go源碼實現(xiàn)使用多線程并發(fā)下載大文件的功能的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包