编程网今天将给大家带来《通道挂起,可能没有在正确的位置关闭》,感兴趣的朋友请继续看下去吧!以下内容将会涉及到等等知识点,如果你是正在学习Golang或者已经是大佬级别了,都非常欢迎也希望大家都能给我建议评论哈~希望能帮助到大家!
问题内容我正在尝试一边编写小程序一边学习go。程序应尽可能高效、快速地递归解析 path,并输出完整文件名(包含路径)和文件的 sha256 文件哈希。
如果文件哈希生成失败,我想保留错误并将其添加到字符串(在哈希位置)。
结果应在控制台上返回一个字符串,如下所示: 文件xyz||哈希
不幸的是,程序在某些时候挂起。我想我的一些频道没有正确关闭并无限期地等待输入。我已经尝试了很长一段时间来解决这个问题,但没有成功。
有人知道为什么输出挂起吗?提前致谢,也欢迎 go 新手的任何意见/建议;-)。
(我编写了单独的函数,因为我想在解决此问题后添加其他功能。)
非常感谢! 迪迪埃
这是代码:
import (
"crypto/sha256"
"encoding/hex"
"flag"
"fmt"
"io"
"log"
"os"
"path/filepath"
"time"
)
func main() {
pathParam := flag.String("path", ".", "Enter Filesystem Path to list folders")
flag.Parse()
start := time.Now()
run(*pathParam)
elapsed := time.Since(start)
log.Printf("Time elapsed: %v", elapsed)
}
func run(path string) {
chashes := make(chan string, 50)
cfiles := make(chan string)
go func() {
readfs(path, cfiles)
defer close(cfiles)
}()
go func() {
generateHash(cfiles, chashes)
}()
defer close(chashes)
for hash := range chashes {
fmt.Println(hash)
}
}
func readfs(path string, cfiles chan string) {
files, err := os.ReadDir(path)
if err != nil {
log.Fatalln(err)
}
for _, file := range files {
filename := filepath.Join(path, file.Name())
if file.IsDir() {
readfs(filename, cfiles)
continue
} else {
cfiles <- filename
}
}
}
func generateHash(cfiles chan string, chashes chan string) {
for filename := range cfiles {
go func(filename string) {
var checksum string
var oError bool = false
file, err := os.Open(filename)
if err != nil {
oError = true
errorMsg := "ERROR: " + err.Error()
log.Println(errorMsg)
checksum = errorMsg
}
defer file.Close()
if !oError {
hash := sha256.New()
if _, err := io.Copy(hash, file); err != nil {
errorMsg := "ERROR: " + err.Error()
log.Println(errorMsg)
checksum = errorMsg
}
if len(checksum) == 0 {
checksum = hex.EncodeToString(hash.Sum(nil))
}
}
chashes <- filename + "||" + checksum
}(filename)
} //for files
}
正确答案
以下循环挂起,因为 chashes
未关闭。
for hash := range chashes {
fmt.println(hash)
}
在所有哈希器完成后,通过关闭 chashes
来修复。使用sync.waitgroup等待哈希器完成。
func generateHash(cfiles chan string, chashes chan string) {
var wg sync.WaitGroup
for filename := range cfiles {
wg.Add(1)
go func(filename string) {
defer wg.Done()
var checksum string
var oError bool = false
file, err := os.Open(filename)
if err != nil {
oError = true
errorMsg := "ERROR: " + err.Error()
log.Println(errorMsg)
checksum = errorMsg
}
defer file.Close()
if !oError {
hash := sha256.New()
if _, err := io.Copy(hash, file); err != nil {
errorMsg := "ERROR: " + err.Error()
log.Println(errorMsg)
checksum = errorMsg
}
if len(checksum) == 0 {
checksum = hex.EncodeToString(hash.Sum(nil))
}
}
chashes <- filename + "||" + checksum
}(filename)
} //for files
// Wait for the hashers to complete.
wg.Wait()
// Close the channel to cause main() to break
// out of for range on chashes.
close(chashes)
}
从 run()
中删除 defer close(chashes)
。
Run an example on the Go playground。
终于介绍完啦!小伙伴们,这篇关于《通道挂起,可能没有在正确的位置关闭》的介绍应该让你收获多多了吧!欢迎大家收藏或分享给更多需要学习的朋友吧~编程网公众号也会发布Golang相关知识,快来关注吧!