Golang递归函数怎么实现并发?

在开发一个运维管理系统时,一个模块中要实现一个批量处理并删除某个目录下的每一个文件的功能。
想法是用递归算法遍历目录下的子目录和每一个文件,在处理每一个文件的时候单开协程来并发处理。
自己写了一个demo,但发现每次都还没处理完目录下的文件就开始删目录而导致死锁。
因为删除目录的代码也是在递归函数里面的,所以我不知道该什么时候从通道里读数据出来。

删除并发的几行代码可以单线程正常工作实现功能,就是不知道怎么搞多并发,大家给个建议来讨论下呗。

阅读 6.9k
2 个回答
package segment

import (
    "errors"
    "fmt"
    "io/ioutil"
    "os"
    "path/filepath"
    "sync"
)

func DeleteDir(filedir string) error {
    var w sync.WaitGroup
    filelist, err := ioutil.ReadDir(filedir)
    if err != nil {
        return err
    }
    for _, value := range filelist {
        if value.IsDir() {
            w.Add(1)
            go func(name string) {
                defer w.Done()
                DeleteDir(filepath.Join(filedir, name))
            }(value.Name())
        } else {
            w.Add(1)
            go func(name string) {
                defer w.Done()
                DeleteFile(filepath.Join(filedir, name))
            }(value.Name())
        }
    }
    w.Wait()
    err = os.Remove(filedir)
    if err != nil {
        fmt.Printf("remove file error : %s \n", err.Error())
    }
    return err
}

func DeleteDirAll(filedir string) error {
    if IsDir(filedir) {
        err := DeleteDir(filedir)
        if err != nil {
            fmt.Printf("delete dir failed : %s \n", err.Error())
            return err
        }
        return nil
    } else {
        return DeleteFile(filedir)
    }
}

func DeleteFile(filename string) error {
    if IsExist(filename) {
        return os.Remove(filename)
    }
    return errors.New("file not exist")
}

func IsDir(filename string) bool {
    fi, err := os.Stat(filename)
    if err != nil {
        return false
    }
    if fi == nil {
        return false
    }
    if fi.IsDir() {
        return true
    }
    return false
}

func IsExist(filename string) bool {
    fi, err := os.Stat(filename)
    if err != nil {
        fmt.Printf("file path not exist : %s \n", err.Error())
        return false
    }
    if fi != nil {
        return true
    }
    return false
}

使用filepath.Glob+ 带缓冲的channel:

package main

import (
    "fmt"
    "path/filepath"
    "sync"
)

func main() {
    ls, err := filepath.Glob("*") // 获取顶层文件/文件夹
    CheckErr(err)

    wg := new(sync.WaitGroup)
    ch := make(chan string, 5)

    go DeleteFile(ch, wg)

    for _, v := range ls {
        wg.Add(1)

        ch <- v
    }

    close(ch)

    wg.Wait()
}

func DeleteFile(ch chan string, wg *sync.WaitGroup) {
    for v := range ch {
        fmt.Println("to remove : ", v)
        wg.Done()
    }
}

func CheckErr(err error) {
    if err != nil {
        panic(err)
    }
}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题