go - 使用 goroutines 复制子目录

标签 go

我的程序将多个文件和目录从计算机的不同部分复制到一个地方。

其中一个目录很大,所以复制它大约需要20-30秒。现在我只是制作了这个方法,它复制该目录以作为 goroutine 启动:

func CopySpecificDirectory(source, dest string, quit chan int) (err error) {
    files, err := os.Open(source)
    file, err := files.Readdir(0)

    if err != nil {
        fmt.Printf("Error reading directory %s: %s\n", source, err)
        return err
    }

    for _, f := range file {
        if f.IsDir() {
            copy.CopyDir(source+"\\"+f.Name(), dest+"\\"+f.Name())
        } else {
            copy.CopyFile(source+"\\"+f.Name(), dest+"\\"+f.Name())
        }
    }

    quit <- 1

    return nil
}

主要:

quit := make(chan int)
go CopySpecificDirectory(config.Location+"\\Directory", config.Destination, quit)

这只是将我的程序改进了几秒钟。在我的 CopySpecificDirectory 方法中(如果这是最好的方法)我想为每个目录创建一个 goroutine,可能是这样的:

c := make(chan int)
for _, f := range file {
    if f.IsDir() {
        go func() {
            copy.CopyDir(source+"\\"+f.Name(), dest+"\\"+f.Name())
            c <- 1
        }()
    } else {
        copy.CopyFile(source+"\\"+f.Name(), dest+"\\"+f.Name())
    }
}

使用这种方法,我不知道在哪里等待每个目录的复制完成 (<- c)。
这是最好的方法吗?如果有人有其他建议,复制目录的最快方法是什么,我很乐意听取。

编辑:

我使用了来自网站的 sync.WaitGroup 示例的方法。

for _, f := range file {
    if f.IsDir() {
        wg.Add(1)
        go func() {
            defer wg.Done()
            copy.CopyDir(source+"\\"+f.Name(), dest+"\\"+f.Name())
        }()
    // more code

我已将 var wg sync.WaitGroup 声明为全局,并且在我调用 CopySpecificDirectory 后立即在 main 中执行 wg.Wait() .

但是 CopySpecificDirectory 在复制所有内容之前完成。我究竟做错了什么 ?看起来它没有等待 goroutines 完成。

最佳答案

使用sync.WaitGroup()而不是 channel :

  1. 创建一个 WaitGroup 对象。
  2. 在产生一个 goroutine 之前,Add() 一个给它。
  3. 当一个 goroutine 即将退出时,它会对该对象调用 Done()
  4. 在您的主(等待)代码中,对该对象调用Wait()。一旦所有以这种方式“跟踪”的 goroutine 完成执行,此函数将返回。

请注意,您的程序是 I/O 绑定(bind)的,而不是 CPU 绑定(bind)的。如果您的代码需要将文件从物理上不同的设备复制到(其他)物理上不同的设备,您可以节省一些时间。如果你只是在同一个文件系统上移动文件,或者你所有的源都在同一个文件系统上,或者你所有的目的地都在同一个文件系统上,你不会得到太多,因为你的 goroutines 只会竞争单个共享资源— 存储设备 — 最终结果与您只是按顺序执行复制操作时的情况不会有太大不同。

举个例子,/etc/fstab 文件的手册页包含有关经典 Unix 系统上已挂载/可挂载文件系统的信息,其中提到操作系统从不检查位于同一物理介质上的文件系统同时 - 仅按顺序进行,同时它会并行检查位于不同驱动器上的文件系统。请参阅 manual page 中的 fs_passno 参数条目.

关于go - 使用 goroutines 复制子目录,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21459457/

相关文章:

html - Go 可以在它所服务的 HTML 文档中捕获点击事件吗?

go - 在反向代理中响应正确的客户端

go - 看不到 struct Golang 的公共(public)函数

json - 如何将JSON字符串转换为结构

docker - Golang Docker 容器未在 Docker-Compose 中重新启动

go - 最小 Go OpenGL 程序段错误

mysql - 去和 mysql 和 cloneTLSConfig

pointers - 范围内的 golang 指针不起作用

interface - 将任意 Golang 接口(interface)转换为字节数组

go - 如何在客户端机器上运行 Go 文件?