都说 go 简单 小白学完 channel 马上就不会了
source link: https://www.v2ex.com/t/850955
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
到 v 上请教下各位大佬. 刚学完 channel 的部分, 就想自己出题考考自己. 任务比较简单, 就是将文件夹下的不同类型的文件移动到对应的子文件夹下面. 例如文件夹 A
包含文件 foo.raw, bar.raw, foo.jpg, bar.jpg
执行后会将 .raw
文件都移动到 raw
文件夹下, 而 .jpg
都会移动到 jpg
文件夹下
我写单线程的还算能搞定, 大体如下
fs, err := ioutil.ReadDir(filepath)
// err 处理略
typeDict := make(map[string]int)
for _, fileinfo := range fs{
slices := strings.Split(fileinfo.Name(), ".")
type := slice[len(slice) - 1]
if _, ok := typeDict[type]; ok {
moveFile()
} else {
createFolder()
moveFile()
typeDict[type] = 1
}
思路比较直白, 就是先获得所有文件信息, 然后遍历获得每个文件的后缀. 如果有同名文件夹, 就把文件挪到这个文件夹里; 如果没有文件夹, 就先创建文件夹然后再移动并打个标记告知已经创建该文件夹 当然会有些边界没有考虑, 比如 文件、文件夹 混合出现, 多级文件夹等情况, 这里先忽略掉
现在想并行执行这个任务, 用 goroutine 和 channel 要怎么完成呢
看完教程, 我的理解是:
既然要用 channel, 那就会有 sender
和 receiver
一对收发的东西
于是我就创建了一个 getInfo
和 一个 dealInfo
函数如下
func getInfo(f []fs.FileInfo, c chan string) {
for _, fs := range f {
if fs.IsDir() || strings.HasPrefix(fs.Name(), ".") {
continue
} else {
c <- fs.Name()
}
}
}
func dealInfo(path string, typeDict map[string]int, c chan string) {
// var name string
for name := range c {
// name = <-c
sp := strings.Split(name, ".")
suffix := sp[len(sp)-1]
if _, ok := typeDict[suffix]; ok {
MoveFile(name, path, suffix)
} else {
CreateFolder(path, suffix)
MoveFile(name, path, suffix)
typeDict[suffix] = 1
fmt.Println(name)
}
}
}
getInfo
不停从切片里面读数据并放到 c
里面, 然后 dealInfo
又不停从 c
里面拿到文件名并作相应的处理. 这看起来 一发一收, 好像没毛病啊, 但是我在 main
里面执行 go getInfo()
和 go dealInfo()
的时候, 怎么文件夹里面什么事情也没发生呢?
我查了一下, 这种情况是子函数还来不及运行主函数就退出导致的. main()
尾部加上一个 time.Sleep
就可以解决. 但是这肯定不是标准做法, 这种情况一般会怎么做呢, 请大佬指教
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK