英文:
Synchronising writes to io.MultiWriter in golang
问题
我正在开发一个应用程序,它应该能够同时写入bytes.Buffer和os.Stdout/os.Stderr。
因此,我创建了一个:
w := io.MultiWriter(myBuf, os.Stdout)
这些写操作将来自多个goroutine。
为了使我的bytes.Buffer至少是线程安全的,我进行了封装:
type Buffer struct {
buffer bytes.Buffer
mutex sync.Mutex
}
func (s *Buffer) Write(p []byte) (n int, err error) {
s.mutex.Lock()
defer s.mutex.Unlock()
return s.buffer.Write(p)
}
func (s *Buffer) String() string {
s.mutex.Lock()
defer s.mutex.Unlock()
return s.buffer.String()
}
如何使用标准错误/输出写入实现相同的结果?
我考虑使用log,但它没有实现io.Writer接口。
英文:
I am working on an app that should be able to write to both a bytes.Buffer as well to os.Stdout / os.Stderr.
Therefore I am creating an
w := io.MultiWriter(myBuf, os.Stdout)
The writes will be from multiple goroutines.
To make at least my bytes.Buffer thread safe, I am wrapping it
type Buffer struct {
buffer bytes.Buffer
mutex sync.Mutex
}
func (s *Buffer) Write(p []byte) (n int, err error) {
s.mutex.Lock()
defer s.mutex.Unlock()
return s.buffer.Write(p)
}
func (s *Buffer) String() string {
s.mutex.Lock()
defer s.mutex.Unlock()
return s.buffer.String()
}
How can I achieve the same result with the standard error / output writes?
I thought about using log but it does not implement the io.Writer interface.
答案1
得分: 1
如何使用标准错误/输出写入来实现相同的结果?
使用互斥锁(mutex),就像你说的那样。
我考虑过使用日志(log),但它没有实现io.Writer接口。
有趣的想法,因为它会自动锁定自身,但你可以使用普通的os.Stdout和os.Stderr来实现,它们都实现了io.Writer接口:
package main
import (
"fmt"
"io"
"os"
"sync"
)
type LockedWriter struct {
w io.Writer
l sync.Mutex
}
func (lw *LockedWriter) Write(p []byte) (n int, err error) {
lw.l.Lock()
defer lw.l.Unlock()
return lw.w.Write(p)
}
func main() {
var wg sync.WaitGroup
var w = &LockedWriter{
w: io.MultiWriter(os.Stdout, os.Stderr),
}
for i := 0; i < 10; i++ {
wg.Add(1)
go func(i int) {
for j := 0; j < i; j++ {
fmt.Fprintf(w, "I am goroutine %d (%d/%d)\n", i, j, i)
}
wg.Done()
}(i)
}
wg.Wait()
}
在这种特定情况下,我无法复现任何插入写入,但我认为如果消息足够长或goroutine执行更多操作,就会出现插入写入。
英文:
> How can I achieve the same result with the standard error / output writes?
With a mutex, like you said.
> I thought about using log but it does not implement the io.Writer interface.
Interesting idea, since it locks itself, but you can do this with plain old os.Stdout and os.Stderr, both of which implement io.Writer:
package main
import (
"fmt"
"io"
"os"
"sync"
)
type LockedWriter struct {
w io.Writer
l sync.Mutex
}
func (lw *LockedWriter) Write(p []byte) (n int, err error) {
lw.l.Lock()
defer lw.l.Unlock()
return lw.w.Write(p)
}
func main() {
var wg sync.WaitGroup
var w = &LockedWriter{
w: io.MultiWriter(os.Stdout, os.Stderr),
}
for i := 0; i < 10; i++ {
wg.Add(1)
go func(i int) {
for j := 0; j < i; j++ {
fmt.Fprintf(w, "I am goroutine %d (%d/%d)\n", i, j, i)
}
wg.Done()
}(i)
}
wg.Wait()
}
In this particular case, I couldn't reproduce any interpolated writes, but I think if the messages were long enough or the goroutines were doing more operations, I would.
答案2
得分: 0
这将有所帮助:
type StdoutType {
stdout *File
mutex sync.Mutex
}
func NewStdoutType() *StdoutType {
return &StdoutType{
stdout: os.Stdout,
}
}
func (s *StdoutType) Write(p []byte) (n int, err error) {
s.mutex.Lock()
defer s.mutex.Unlock()
return s.stdout.Write(p)
}
StdoutType 现在与 io.Writer 兼容。
英文:
Will this help:
type StdoutType {
stdout *File
mutex sync.Mutex
}
func NewStdoutType() *StdoutType {
return &StdoutType{
stdout: os.Stdout,
}
}
func (s *StdoutType) Write(p []byte) (n int, err error) {
s.mutex.Lock()
defer s.mutex.Unlock()
return s.stdout.Write(p)
}
StdoutType is now io.Writer compatible
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论