golang中處理多個文件同時上傳以及文件上傳速度優(yōu)化

首先給大家推薦一本書Go in Practice概漱,通過一個個超級小巧而又非常實戰(zhàn)的案例提升golang內(nèi)功。
TECHNIQUE 48 Incrementally saving a file中猪半,向讀者講述了如何處理多個文件同時提交的處理方法
以下代碼和文中略有不同:

func uploadBigFile(w http.ResponseWriter, r *http.Request) {
    mr, err := r.MultipartReader()
    if err != nil {
        fmt.Sprintln(err)
        fmt.Fprintln(w, err)

        return
    }

    values := make(map[string][]string, 0)
    maxValueBytes := int64(10 << 20)
    for {
        part, err := mr.NextPart()
        if err == io.EOF {
            break
        }

        name := part.FormName()
        if name == "" {
            continue
        }

        fileName := part.FileName()

        var b bytes.Buffer

        if fileName == "" {
            n, err := io.CopyN(&b, part, maxValueBytes)
            if err != nil && err != io.EOF {
                fmt.Sprintln(err)
                fmt.Fprintln(w, err)

                return
            }

            maxValueBytes -= n
            if maxValueBytes <= 0 {
                msg := "multipart message too large"
                fmt.Fprint(w, msg)
                return
            }

            values[name] = append(values[name], b.String())
        }

        dst, err := os.Create("/tmp/upload/" + fileName)
        defer dst.Close()

        for {
            buffer := make([]byte, 100000)
            cBytes, err := part.Read(buffer)
            if err == io.EOF {
                break
            }
            dst.Write(buffer[0:cBytes])
        }

    }
}

在進(jìn)行benchmark測試的時候匾南,發(fā)現(xiàn)上述方式在處理單個文件上傳的時候要比普通的處理方法要快
普通的文件上傳處理接口


func upload(w http.ResponseWriter, r *http.Request) {
    file, head, err := r.FormFile("my_file")
    if err != nil {
        fmt.Sprintln(err)
        fmt.Fprintln(w, err)

        return
    }

    localFileDir := "/tmp/upload/"
    err = os.MkdirAll(localFileDir, 0777)
    if err != nil {
        fmt.Sprintln(err)
        fmt.Fprintln(w, err)

        return
    }

    localFilePath := localFileDir + head.Filename

    localFile, err := os.Create(localFilePath)
    if err != nil {
        fmt.Sprintln(err)
        fmt.Fprintln(w, err)

        return
    }
    defer localFile.Close()

    io.Copy(localFile, file)
    fmt.Fprintln(w, localFilePath)

}

基準(zhǔn)測試代碼


func BenchmarkUpload(b *testing.B) {

    for i := 0; i < b.N; i++ {
        path := "/home/kes/code_1.13.1-1497464373_amd64.deb"
        file, err := os.Open(path)
        if err != nil {
            b.Error(err)
        }

        defer file.Close()
        body := &bytes.Buffer{}
        writer := multipart.NewWriter(body)
        part, err := writer.CreateFormFile("my_file", filepath.Base(path))
        if err != nil {
            b.Error(err)
        }
        io.Copy(part, file)
        writer.Close()

        req := httptest.NewRequest("POST", "/upload", body)
        req.Header.Set("Content-Type", writer.FormDataContentType())
        res := httptest.NewRecorder()

        upload(res, req)

        if res.Code != http.StatusOK {
            b.Error("not 200")
        }
    }

    // t.Log(res.Body.String())
    // t.Log(io.read)

}

func BenchmarkUploadBig(b *testing.B) {

    for i := 0; i < b.N; i++ {
        path := "/home/kes/code_1.13.1-1497464373_amd64.deb"
        file, err := os.Open(path)
        if err != nil {
            b.Error(err)
        }

        defer file.Close()
        body := &bytes.Buffer{}
        writer := multipart.NewWriter(body)
        part, err := writer.CreateFormFile("my_file", filepath.Base(path))
        if err != nil {
            b.Error(err)
        }
        io.Copy(part, file)
        writer.Close()

        req := httptest.NewRequest("POST", "/upload", body)
        req.Header.Set("Content-Type", writer.FormDataContentType())
        res := httptest.NewRecorder()

        uploadBigFile(res, req)

        if res.Code != http.StatusOK {
            b.Error("not 200")
        }
    }

    // t.Log(res.Body.String())
    // t.Log(io.read)

}

測試的文件大小大概44M
測試結(jié)果

$ go test -bench="." -v
BenchmarkUpload-4              1        1074491528 ns/op
BenchmarkUploadBig-4           2         517001745 ns/op
PASS
ok      _/home/kes/test    2.966s

$ go test -bench="." -v
BenchmarkUpload-4              1        1295672144 ns/op
BenchmarkUploadBig-4           2         537212487 ns/op
PASS
ok      _/home/kes/test    3.218s
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市迫淹,隨后出現(xiàn)的幾起案子示括,更是在濱河造成了極大的恐慌铺浇,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,378評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件垛膝,死亡現(xiàn)場離奇詭異鳍侣,居然都是意外死亡,警方通過查閱死者的電腦和手機吼拥,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,970評論 3 399
  • 文/潘曉璐 我一進(jìn)店門倚聚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人凿可,你說我怎么就攤上這事惑折。” “怎么了枯跑?”我有些...
    開封第一講書人閱讀 168,983評論 0 362
  • 文/不壞的土叔 我叫張陵惨驶,是天一觀的道長。 經(jīng)常有香客問我敛助,道長粗卜,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,938評論 1 299
  • 正文 為了忘掉前任纳击,我火速辦了婚禮休建,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘评疗。我一直安慰自己,他們只是感情好茵烈,可當(dāng)我...
    茶點故事閱讀 68,955評論 6 398
  • 文/花漫 我一把揭開白布百匆。 她就那樣靜靜地躺著,像睡著了一般呜投。 火紅的嫁衣襯著肌膚如雪加匈。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,549評論 1 312
  • 那天仑荐,我揣著相機與錄音雕拼,去河邊找鬼。 笑死粘招,一個胖子當(dāng)著我的面吹牛啥寇,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 41,063評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼辑甜,長吁一口氣:“原來是場噩夢啊……” “哼衰絮!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起磷醋,我...
    開封第一講書人閱讀 39,991評論 0 277
  • 序言:老撾萬榮一對情侶失蹤猫牡,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后邓线,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體淌友,經(jīng)...
    沈念sama閱讀 46,522評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,604評論 3 342
  • 正文 我和宋清朗相戀三年骇陈,在試婚紗的時候發(fā)現(xiàn)自己被綠了震庭。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,742評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡缩歪,死狀恐怖归薛,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情匪蝙,我是刑警寧澤主籍,帶...
    沈念sama閱讀 36,413評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站逛球,受9級特大地震影響千元,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜颤绕,卻給世界環(huán)境...
    茶點故事閱讀 42,094評論 3 335
  • 文/蒙蒙 一幸海、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧奥务,春花似錦物独、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,572評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至帚称,卻和暖如春官研,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背闯睹。 一陣腳步聲響...
    開封第一講書人閱讀 33,671評論 1 274
  • 我被黑心中介騙來泰國打工戏羽, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人楼吃。 一個月前我還...
    沈念sama閱讀 49,159評論 3 378
  • 正文 我出身青樓始花,卻偏偏與公主長得像妄讯,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子衙荐,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,747評論 2 361

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,317評論 25 707
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理捞挥,服務(wù)發(fā)現(xiàn),斷路器忧吟,智...
    卡卡羅2017閱讀 134,714評論 18 139
  • 本文受唐巧的博文啟發(fā)而成, 并摘錄網(wǎng)上內(nèi)容編寫而成 環(huán)境: Xcode6.3.2GM, OSX 10.10 目錄 ...
    喵小蕊rita閱讀 579評論 0 0
  • 星辰是夜的黑砌函,太陽是晝的白,夜是白的黑溜族。人這一生會遇到遇到很多事讹俊,冷暖自知,卻總是向著太陽煌抒,因為那是溫暖的東西仍劈。 ...
    立里童瞳閱讀 714評論 8 12