stdout 上的并发写入线程安全吗?
这个问题涉及并发写入标准输出(stdout)流的线程安全性去。具体来说,考虑以下代码:
<code class="go">package main import ( "fmt" "os" "strings" ) func main() { x := strings.Repeat(" ", 1024) go func() { for { fmt.Fprintf(os.Stdout, x+"aa\n") } }() go func() { for { fmt.Fprintf(os.Stdout, x+"bb\n") } }() go func() { for { fmt.Fprintf(os.Stdout, x+"cc\n") } }() go func() { for { fmt.Fprintf(os.Stdout, x+"dd\n") } }() <-make(chan bool) }</code>
尽管没有任何明显的数据竞争,但关于此代码的线程安全性仍存在一些争论。为了澄清这个问题,让我们深入研究写入 stdout 的机制并检查建议和参考。
FMT 包和 IO.Writer
fmt 包函数,例如 fmt.Fprintf,接受实现 io.Writer 接口的参数。它们在内部调用此接口的 Write 方法。
操作系统和对 stdout 的并发访问
os.Stdout 是 io.Writer 接口的实现,它将输出定向到系统的标准输出。当多个 goroutine 并发写入 os.Stdout 时,该操作的实际语义将委托给底层操作系统。
在 POSIX 系统中,使用 write(2) 系统调用。 POSIX 指定并发 write(2) 调用对于常规文件和符号链接是原子的。但是,此保证不适用于其他文件类型或非 POSIX 系统。
Go 标准库和包装器
Go 标准库提供了用于写入的包装器文件描述符和套接字。这些包装器实现 io.Writer 接口,并且在 os.Stdout 的情况下,将操作重定向到相关的系统调用。
Go 运行时确保这些包装器对于并发访问在内部是安全的。然而,它们只是将写入转发到底层操作系统,因此并发语义最终由操作系统决定。
并发 stdout 写入的影响
建议
参考文献
以上是在 Go 中写入'stdout”真的是线程安全的吗?的详细内容。更多信息请关注PHP中文网其他相关文章!