dongshui2254 2014-09-08 20:19
浏览 13
已采纳

Golang上传整个目录并返回许多打开的文件

I am trying to upload a whole dir to the server. It works with small directories but whit 100 + pictures it return error "to many open files". I close the file right after it gets read from. Any idea how to fix this?

this is my code

    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条回答 默认 最新

  • dpkt31779 2014-09-08 21:21
    关注

    The original code does not limit the number of active go routines and therefore does not limit the number of open file descriptors. Several operating systems have limits on the number of open file descriptors. The fix is to create a fixed number of worker go routines.

    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
    }
    

    As a bonus, I modified channel sizes and send operations so that goroutines are not stuck when there's an error.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 各位请问平行检验趋势图这样要怎么调整?说标准差差异太大了
  • ¥15 delphi webbrowser组件网页下拉菜单自动选择问题
  • ¥15 wpf界面一直接收PLC给过来的信号,导致UI界面操作起来会卡顿
  • ¥15 init i2c:2 freq:100000[MAIXPY]: find ov2640[MAIXPY]: find ov sensor是main文件哪里有问题吗
  • ¥15 运动想象脑电信号数据集.vhdr
  • ¥15 三因素重复测量数据R语句编写,不存在交互作用
  • ¥15 微信会员卡等级和折扣规则
  • ¥15 微信公众平台自制会员卡可以通过收款码收款码收款进行自动积分吗
  • ¥15 随身WiFi网络灯亮但是没有网络,如何解决?
  • ¥15 gdf格式的脑电数据如何处理matlab