英文:
Is it possible to terminate a Go channel to a sink goroutine?
问题
我有一个goroutine,它以块的形式读取文件,并通过通道传递给另一个goroutine,该goroutine为文件计算校验和。消费goroutine是通道的终点。
在所有字节从通道接收完毕后,是否可能让消费者返回校验和字符串,或者必须使用字符串流来返回值?对于前者,我遇到了死锁问题,但我没有使用任何waitgroup;不确定如何在这种情况下应用它们。
我很感谢您的意见,谢谢您的帮助。
// main()
var done = make(chan bool)
defer close(done)
checksum := FileCheckSum(ReadFileToChannel("mydata4.bin", done), done)
fmt.Println("Final Checksum: ", checksum)
// FileCheckSum()
import (
"crypto/sha256"
"encoding/hex"
"log"
)
func FileCheckSum(cin <-chan []byte, done <-chan bool) string {
chunkStream := make(chan []byte)
checksum := func(in <-chan []byte, done <-chan bool) string {
defer close(chunkStream)
hasher := sha256.New()
for chunk := range in {
_, err := hasher.Write(chunk[:len(chunk)])
if err != nil {
log.Fatal(err)
}
select {
case <-done:
return ""
}
}
return hex.EncodeToString(hasher.Sum(nil))
}(cin, done)
return checksum
}
英文:
I have a goroutine that reads a file in chunks and passes them through a channel to another goroutine that calculates a checksum for the file. The consuming goroutine is kind of a sink for the channel.
Is it possible to have the consumer return the checksum string after all of the bytes have been received from the channel, or must I use a string stream to return the value? For the former, I get a deadlock, but I am not using any waitgroups; Not sure how to apply them in this case.
I'd appreciate your comments and thank you for your help.
// main()
var done = make(chan bool)
defer close(done)
checksum := FileCheckSum(ReadFileToChannel("mydata4.bin", done), done)
fmt.Println("Final Checksum: ", checksum)
// FileCheckSum()
import (
"crypto/sha256"
"encoding/hex"
"log"
)
func FileCheckSum(cin <-chan []byte, done <-chan bool) string {
chunkStream := make(chan []byte)
checksum := func(in <-chan []byte, done <-chan bool) string {
defer close(chunkStream)
hasher := sha256.New()
for chunk := range in {
_, err := hasher.Write(chunk[:len(chunk)])
if err != nil {
log.Fatal(err)
}
select {
case <-done:
return ""
}
}
return hex.EncodeToString(hasher.Sum(nil))
}(cin, done)
return checksum
}
答案1
得分: 1
是的,让我简化你的代码,并阅读以下代码中的注释。请尝试这个链接:
package main
import (
"crypto/rand"
"crypto/sha256"
"encoding/hex"
"fmt"
"log"
)
func FileCheckSum(cin <-chan []byte) string {
h := sha256.New()
for buf := range cin {
_, err := h.Write(buf)
if err != nil {
log.Fatal(err)
}
}
return hex.EncodeToString(h.Sum(nil))
}
func ReadFileToChannel(filename string) chan []byte {
gen := make(chan []byte)
go func() { // goroutine
defer close(gen) // signal end of reading file
for i := 0; i < 10; i++ { // e.g. read from file
b := make([]byte, 16) // make new slice every time
_, err := rand.Read(b) // fill it
if err != nil {
log.Fatal(err)
}
gen <- b // send it
}
}()
return gen
}
func main() {
ch := ReadFileToChannel("mydata4.bin")
crc := FileCheckSum(ch)
fmt.Println("Final Checksum: ", crc)
}
输出结果:
Final Checksum: 1e0ad2ec11bfe77833af670c6de296f530c2217d18aa1b8e600feddf6998fb95
注意:
你的代码需要进行代码审查,你可以前往这里进行代码审查。
英文:
Yes, and let me simplify your code - and read comments inside the following code.
Try this:
package main
import (
"crypto/rand"
"crypto/sha256"
"encoding/hex"
"fmt"
"log"
)
func FileCheckSum(cin <-chan []byte) string {
h := sha256.New()
for buf := range cin {
_, err := h.Write(buf)
if err != nil {
log.Fatal(err)
}
}
return hex.EncodeToString(h.Sum(nil))
}
func ReadFileToChannel(filename string) chan []byte {
gen := make(chan []byte)
go func() { // goroutine
defer close(gen) // signal end of reading file
for i := 0; i < 10; i++ { // e.g. read from file
b := make([]byte, 16) // make new slice every time
_, err := rand.Read(b) // fill it
if err != nil {
log.Fatal(err)
}
gen <- b // send it
}
}()
return gen
}
func main() {
ch := ReadFileToChannel("mydata4.bin")
crc := FileCheckSum(ch)
fmt.Println("Final Checksum: ", crc)
}
Output:
Final Checksum: 1e0ad2ec11bfe77833af670c6de296f530c2217d18aa1b8e600feddf6998fb95
Note
Your code needs a code review, you may head over here for the code review.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论