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

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

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(&quot;mydata4.bin&quot;, done), done)
	fmt.Println(&quot;Final Checksum: &quot;, checksum)
// FileCheckSum()
import (
	&quot;crypto/sha256&quot;
	&quot;encoding/hex&quot;
	&quot;log&quot;
)

func FileCheckSum(cin &lt;-chan []byte, done &lt;-chan bool) string {

	chunkStream := make(chan []byte)
	checksum := func(in &lt;-chan []byte, done &lt;-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 &lt;-done:
				return &quot;&quot;
			}
		}

		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 (
	&quot;crypto/rand&quot;
	&quot;crypto/sha256&quot;
	&quot;encoding/hex&quot;
	&quot;fmt&quot;
	&quot;log&quot;
)

func FileCheckSum(cin &lt;-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 &lt; 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 &lt;- b // send it
		}
	}()
	return gen
}

func main() {
	ch := ReadFileToChannel(&quot;mydata4.bin&quot;)
	crc := FileCheckSum(ch)
	fmt.Println(&quot;Final Checksum: &quot;, crc)
}

Output:

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:

确定