可以将Go通道终止到一个接收(sink)的goroutine吗?

huangapple go评论121阅读模式
英文:

Is it possible to terminate a Go channel to a sink goroutine?

问题

我有一个goroutine,它以块的形式读取文件,并通过通道传递给另一个goroutine,该goroutine为文件计算校验和。消费goroutine是通道的终点。

在所有字节从通道接收完毕后,是否可能让消费者返回校验和字符串,或者必须使用字符串流来返回值?对于前者,我遇到了死锁问题,但我没有使用任何waitgroup;不确定如何在这种情况下应用它们。

我很感谢您的意见,谢谢您的帮助。

  1. // main()
  2. var done = make(chan bool)
  3. defer close(done)
  4. checksum := FileCheckSum(ReadFileToChannel("mydata4.bin", done), done)
  5. fmt.Println("Final Checksum: ", checksum)
  1. // FileCheckSum()
  2. import (
  3. "crypto/sha256"
  4. "encoding/hex"
  5. "log"
  6. )
  7. func FileCheckSum(cin <-chan []byte, done <-chan bool) string {
  8. chunkStream := make(chan []byte)
  9. checksum := func(in <-chan []byte, done <-chan bool) string {
  10. defer close(chunkStream)
  11. hasher := sha256.New()
  12. for chunk := range in {
  13. _, err := hasher.Write(chunk[:len(chunk)])
  14. if err != nil {
  15. log.Fatal(err)
  16. }
  17. select {
  18. case <-done:
  19. return ""
  20. }
  21. }
  22. return hex.EncodeToString(hasher.Sum(nil))
  23. }(cin, done)
  24. return checksum
  25. }
英文:

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.

  1. // main()
  2. var done = make(chan bool)
  3. defer close(done)
  4. checksum := FileCheckSum(ReadFileToChannel(&quot;mydata4.bin&quot;, done), done)
  5. fmt.Println(&quot;Final Checksum: &quot;, checksum)
  1. // FileCheckSum()
  2. import (
  3. &quot;crypto/sha256&quot;
  4. &quot;encoding/hex&quot;
  5. &quot;log&quot;
  6. )
  7. func FileCheckSum(cin &lt;-chan []byte, done &lt;-chan bool) string {
  8. chunkStream := make(chan []byte)
  9. checksum := func(in &lt;-chan []byte, done &lt;-chan bool) string {
  10. defer close(chunkStream)
  11. hasher := sha256.New()
  12. for chunk := range in {
  13. _, err := hasher.Write(chunk[:len(chunk)])
  14. if err != nil {
  15. log.Fatal(err)
  16. }
  17. select {
  18. case &lt;-done:
  19. return &quot;&quot;
  20. }
  21. }
  22. return hex.EncodeToString(hasher.Sum(nil))
  23. }(cin, done)
  24. return checksum
  25. }

答案1

得分: 1

是的,让我简化你的代码,并阅读以下代码中的注释。请尝试这个链接

  1. package main
  2. import (
  3. "crypto/rand"
  4. "crypto/sha256"
  5. "encoding/hex"
  6. "fmt"
  7. "log"
  8. )
  9. func FileCheckSum(cin <-chan []byte) string {
  10. h := sha256.New()
  11. for buf := range cin {
  12. _, err := h.Write(buf)
  13. if err != nil {
  14. log.Fatal(err)
  15. }
  16. }
  17. return hex.EncodeToString(h.Sum(nil))
  18. }
  19. func ReadFileToChannel(filename string) chan []byte {
  20. gen := make(chan []byte)
  21. go func() { // goroutine
  22. defer close(gen) // signal end of reading file
  23. for i := 0; i < 10; i++ { // e.g. read from file
  24. b := make([]byte, 16) // make new slice every time
  25. _, err := rand.Read(b) // fill it
  26. if err != nil {
  27. log.Fatal(err)
  28. }
  29. gen <- b // send it
  30. }
  31. }()
  32. return gen
  33. }
  34. func main() {
  35. ch := ReadFileToChannel("mydata4.bin")
  36. crc := FileCheckSum(ch)
  37. fmt.Println("Final Checksum: ", crc)
  38. }

输出结果:

  1. Final Checksum: 1e0ad2ec11bfe77833af670c6de296f530c2217d18aa1b8e600feddf6998fb95

注意:
你的代码需要进行代码审查,你可以前往这里进行代码审查。

英文:

Yes, and let me simplify your code - and read comments inside the following code.
Try this:

  1. package main
  2. import (
  3. &quot;crypto/rand&quot;
  4. &quot;crypto/sha256&quot;
  5. &quot;encoding/hex&quot;
  6. &quot;fmt&quot;
  7. &quot;log&quot;
  8. )
  9. func FileCheckSum(cin &lt;-chan []byte) string {
  10. h := sha256.New()
  11. for buf := range cin {
  12. _, err := h.Write(buf)
  13. if err != nil {
  14. log.Fatal(err)
  15. }
  16. }
  17. return hex.EncodeToString(h.Sum(nil))
  18. }
  19. func ReadFileToChannel(filename string) chan []byte {
  20. gen := make(chan []byte)
  21. go func() { // goroutine
  22. defer close(gen) // signal end of reading file
  23. for i := 0; i &lt; 10; i++ { // e.g. read from file
  24. b := make([]byte, 16) // make new slice every time
  25. _, err := rand.Read(b) // fill it
  26. if err != nil {
  27. log.Fatal(err)
  28. }
  29. gen &lt;- b // send it
  30. }
  31. }()
  32. return gen
  33. }
  34. func main() {
  35. ch := ReadFileToChannel(&quot;mydata4.bin&quot;)
  36. crc := FileCheckSum(ch)
  37. fmt.Println(&quot;Final Checksum: &quot;, crc)
  38. }

Output:

  1. Final Checksum: 1e0ad2ec11bfe77833af670c6de296f530c2217d18aa1b8e600feddf6998fb95

Note

Your code needs a code review, you may head over here for the code review.

huangapple
  • 本文由 发表于 2022年1月29日 13:28:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/70902556.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定