亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

Golang上傳整個目錄并發返回許多打開的文件

Golang上傳整個目錄并發返回許多打開的文件

Go
森林海 2021-08-16 16:08:08
我正在嘗試將整個目錄上傳到服務器。它適用于小目錄,但有 100 多張圖片,它返回“許多打開的文件”錯誤。我在讀取文件后立即關閉該文件。知道如何解決這個問題嗎?這是我的代碼    func uploadDir(path string) error {    dir, err := os.Open(path)    if err != nil {        return err    }    files, err := dir.Readdirnames(-1)    if err != nil {        return err    }    dir.Close()    errChan := make(chan error)    resChan := make(chan *client.PutResult)    remaining := len(files)    for _, file := range files {        file := file        go func() {            file, err := os.Open(path + "/" + file)            if err != nil {                errChan <- err            }            c := client.NewClient(os.Getenv("DROPS_SERVER"))            res, err := c.Upload(client.NewUploadHandleFromReader(file))            file.Close()            if err != nil {                errChan <- err            }            resChan <- res        }()    }    for {        select {        case res := <-resChan:            log.Println(res)            remaining--        case err := <-errChan:            if err != nil {                return err            }        }        if remaining == 0 {            break        }    }    return nil}
查看完整描述

2 回答

?
慕雪6442864

TA貢獻1812條經驗 獲得超5個贊

原始代碼不限制活動 go 例程的數量,因此不限制打開的文件描述符的數量。一些操作系統對打開的文件描述符的數量有限制。解決方法是創建固定數量的工作程序 go 例程。


func uploadDir(path string) error {


    // Read directory and close.


    dir, err := os.Open(path)

    if err != nil {

        return err

    }

    names, err := dir.Readdirnames(-1)

    if err != nil {

        return err

    }

    dir.Close()


    // Copy names to a channel for workers to consume. Close the

    // channel so that workers stop when all work is complete.


    namesChan := make(chan string, len(names))

    for _, name := range names {

        namesChan <- name

    }

    close(namesChan)


    // Create a maximum of 8 workers


    workers := 8

    if len(names) < workers {

        workers = len(names)

    }


    errChan := make(chan error, 1)

    resChan := make(chan *client.PutResult, len(names))


    // Run workers


    for i := 0; i < workers; i++ {

        go func() {

            // Consume work from namesChan. Loop will end when no more work.

            for name := range namesChan {

                file, err := os.Open(filepath.Join(path, name))

                if err != nil {

                    select {

                    case errChan <- err:

                        // will break parent goroutine out of loop

                    default:

                       // don't care, first error wins

                    }

                    return

                }

                c := client.NewClient(os.Getenv("DROPS_SERVER"))

                res, err := c.Upload(client.NewUploadHandleFromReader(file))

                file.Close()

                if err != nil {

                    select {

                    case errChan <- err:

                        // will break parent goroutine out of loop

                    default:

                       // don't care, first error wins

                    }

                    return

                }

                resChan <- res

            }

        }()

    }


    // Collect results from workers 


    for i := 0; i < len(names); i++ {

        select {

        case res := <-resChan:

            log.Println(res)

        case err := <-errChan:

            return err

        }

    }

    return nil

}

作為獎勵,我修改了通道大小并發送操作,以便在出現錯誤時不會卡住 goroutine。


查看完整回答
反對 回復 2021-08-16
  • 2 回答
  • 0 關注
  • 244 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號