Last active
March 17, 2024 07:26
-
-
Save alexmullins/1c6cc6dc38a8e83ed2f6 to your computer and use it in GitHub Desktop.
Concurrent io.MultiWriter Implementation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"crypto/md5" | |
"crypto/sha1" | |
"crypto/sha256" | |
"crypto/sha512" | |
"encoding/hex" | |
"fmt" | |
"io" | |
"strings" | |
) | |
func main() { | |
input := "hello world" | |
fmt.Println("Input:", input) | |
r := strings.NewReader(input) | |
hashes := CalculateBasicHashes(r) | |
fmt.Println("Md5:", hashes.Md5) | |
fmt.Println("Sha1:", hashes.Sha1) | |
fmt.Println("Sha256:", hashes.Sha256) | |
fmt.Println("Sha512:", hashes.Sha512) | |
} | |
type HashInfo struct { | |
Md5 string | |
Sha1 string | |
Sha256 string | |
Sha512 string | |
} | |
func CalculateBasicHashes(rd io.Reader) HashInfo { | |
md5 := md5.New() | |
sha1 := sha1.New() | |
sha256 := sha256.New() | |
sha512 := sha512.New() | |
multiWriter := MultiCWriter(md5, sha1, sha256, sha512) | |
_, err := io.Copy(multiWriter, rd) | |
if err != nil { | |
fmt.Println(err.Error()) | |
} | |
var info HashInfo | |
info.Md5 = hex.EncodeToString(md5.Sum(nil)) | |
info.Sha1 = hex.EncodeToString(sha1.Sum(nil)) | |
info.Sha256 = hex.EncodeToString(sha256.Sum(nil)) | |
info.Sha512 = hex.EncodeToString(sha512.Sum(nil)) | |
return info | |
} | |
type multiCWriter struct { | |
writers []io.Writer | |
} | |
func (t *multiCWriter) Write(p []byte) (n int, err error) { | |
type data struct { | |
n int | |
err error | |
} | |
results := make(chan data) | |
for _, w := range t.writers { | |
go func(wr io.Writer, p []byte, ch chan data) { | |
n, err = wr.Write(p) | |
if err != nil { | |
ch <- data{n, err} | |
return | |
} | |
if n != len(p) { | |
ch <- data{n, io.ErrShortWrite} | |
return | |
} | |
ch <- data{n, nil} //completed ok | |
}(w, p, results) | |
} | |
for range t.writers { | |
d := <-results | |
if d.err != nil { | |
return d.n, d.err | |
} | |
} | |
return len(p), nil | |
} | |
// MultiWriter creates a writer that duplicates its writes to all the | |
// provided writers, similar to the Unix tee(1) command. | |
func MultiCWriter(writers ...io.Writer) io.Writer { | |
w := make([]io.Writer, len(writers)) | |
copy(w, writers) | |
return &multiCWriter{w} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
NoobQn. Is this benchmarked? This article goes in detail as to why concurrency in such a situation would actually be detrimental.