我的程序将多个文件和目录从计算机的不同部分复制到一个地方。
其中一个目录非常大,因此复制它需要大约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())
}
}
通过这种方法,我不知道在哪里等待副本完成每个目录(&lt; -c)。
这是最好的方法吗?如果有人有其他建议什么是复制目录的最快方法,我很乐意听到它。
编辑:
我使用了来自网站的sync.WaitGroup示例的aproach。
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
声明为全球,我在致电wg.Wait()
后在主要权利CopySpecificDirectory
。
但CopySpecificDirectory
在复制所有内容之前完成。我究竟做错了什么 ?看起来它不是在等待goroutines完成。
答案 0 :(得分:1)
使用这种方法,我不知道在哪里等待副本完成每个目录(&lt; -c)。
您可以使用SyncGroup来协调所有goroutine,而不是在频道上发送信号。您为每个衍生的goroutine致电wg.Add(1)
,并在他们完成时致电wg.Done()
。然后你在产生所有这些之后做wg.Wait()
等待它们全部完成。
至于如何加速复制一般,没有明确的答案。这取决于很多因素(可能是操作系统,文件系统,硬盘,负载等)。
答案 1 :(得分:1)
使用sync.WaitGroup()
代替频道:
Add()
生成一个。Done()
。Wait()
。一旦所有goroutine以这种方式“跟踪”完成执行,该函数将返回。请注意,您的程序受I / O限制,而不受CPU限制。如果您的代码需要将文件从物理上不同的设备复制到(其他)物理上不同的设备,那么可以节省一些时间。如果您只是在同一个文件系统上浏览文件,或者您的所有源都在同一个文件系统上,或者您的所有目标位于同一个文件系统上,那么您将无法获得太多收益,因为您的goroutine只会在单个共享资源上竞争 - 存储设备 - 最终结果与您只是按顺序执行复制操作的情况没有太大区别。
为了提供示例,/etc/fstab
文件的手册页包含有关经典Unix系统上已安装/可安装文件系统的信息,提到操作系统从不同时检查位于同一物理介质上的文件系统顺序地,它同时检查位于不同驱动器上的文件系统。请参阅manual page中的fs_passno
参数条目。
答案 2 :(得分:0)
感谢@kostix和@justinas的帮助。我按照他们的解决方案,唯一的问题仍然是我的for循环f内部没有必然绑定,直到循环完成。
所以我必须添加f := f
。这现在有效:
for _, f := range file {
f := f
if f.IsDir() {
wg.Add(1)
go func() {
copy.CopyDir(source+"\\"+f.Name(), dest+"\\"+f.Name())
defer wg.Done()
}()
} else {
copy.CopyFile(source+"\\"+f.Name(), dest+"\\"+f.Name())
}
}