[go]递归函数中的多重读取速度较慢

· 收录于 2024-01-06 06:38:08 · source URL

问题详情

var m sync.Mutex

func recurseDirectoriesMultiThread(wg *sync.WaitGroup, photoPaths *[]string, directory string) {
    defer wg.Done()
    items, _ := os.ReadDir(directory)
    for _, item := range items {
        if item.IsDir() {
            wg.Add(1)
            go recurseDirectoriesMultiThread(wg, photoPaths, directory+"/"+item.Name())
        } else {
            // handle file
            m.Lock()
            *photoPaths = append(*photoPaths, directory+"/"+item.Name())
            m.Unlock()
        }
    }

}
func recurseDirectories(photoPaths *[]string, directory string) {
    items, _ := os.ReadDir(directory)
    for _, item := range items {
        if item.IsDir() {
            recurseDirectories(photoPaths, directory+"/"+item.Name())
        } else {
            // handle file
            *photoPaths = append(*photoPaths, directory+"/"+item.Name())
        }
    }
}

func main() {
    args := os.Args
    fmt.Println(args[1])
    path := args[1]

    stringSlice1 := make([]string, 0) // slice
    start := time.Now()
    recurseDirectories(&stringSlice1, path)
    fmt.Println("Single thread time " + time.Since(start).String())
    fmt.Println("Number of files " + strconv.Itoa(len(stringSlice1)))

    stringSlice2 := make([]string, 0) // slice
    wg := new(sync.WaitGroup)
    wg.Add(1)
    start = time.Now()
    recurseDirectoriesMultiThread(wg, &stringSlice2, path)
    wg.Wait()
    fmt.Println("Mulit thread time " + time.Since(start).String())
    fmt.Println("Number of files " + strconv.Itoa(len(stringSlice2)))
}

我想尝试一个项目来了解更多关于 goroutines 和 channels 的信息。我认为系统文件扫描器获取目录中的所有文件名是一个很酷的主意。虽然现在我看到它可能不像我想象的那么好https://stackoverflow.com/a/41687429/13970153 因为无论我采用何种方法,系统调用级别都会有文件 I/O 锁定。尽管如此,出于某种奇怪的原因,我看到我的多线程方法在这里的性能一直低于普通的递归方法。我以为它至少在某种程度上会更快?

输出:

Mulit thread time 224.196833ms
Number of files 3123
Single thread time 147.0

Mulit thread time 228.218042ms
Number of files 3123
Single thread time 149.666041ms
Number of files 3123

Mulit thread time 185.23275ms
Number of files 3123
Single thread time 147.412958ms
Number of files 3123

有人有什么想法吗?

我没有看到在这里使用通道的原因,因为我可以锁定和解锁 photoPath 的互斥锁。

最佳回答

由于您对公共列表的每个添加都使用了 lock/lock,因此很可能所有 goroutines 都会相互等待写入列表。正因为如此,你的算法并没有真正从多个 goroutine 中受益,因为查找文件所花费的时间与等待写入列表所花费的时间相当。

尝试从每个包含许多文件的 goroutine 返回一个新切片,并使用锁将一个列表附加到另一个列表,然后进行测量。这应该会增加并行性,因为每个 goroutine 将独立工作以填充新的切片。