为了账号安全,请及时绑定邮箱和手机立即绑定

多个 goroutine 会同时调用 Conn 上的方法吗?

多个 goroutine 会同时调用 Conn 上的方法吗?

Go
Cats萌萌 2022-01-17 19:55:11
我的程序是这样的:func handle(conn net.Conn) {    msg := "hello, world!"    for i:= 0; i< 100000; i++ {        go func() {            err := write(conn, msg)        }    }}func write(conn net.Conn, msg string) error {    mlen := fmt.Sprintf("%04d", len(msg))    _, err := conn.Write([]byte(mlen + msg))    return err}该程序将同时运行 100000 个 goroutine,并且所有 goroutine 将向同一个连接发送消息。我怀疑服务器会收到类似“hellohelloworldworld”的错误消息,但是当程序在我的 Ubuntu 14.04LTS 中运行时没有问题。那么,多个 goroutine 会同时调用 Conn 上的方法吗?=========================================================================我怎样才能保持Write方法的原子性?
查看完整描述

2 回答

?
PIPIONE

TA贡献1829条经验 获得超9个赞

该文档指出:

多个 goroutine 可以同时调用 Conn 上的方法。

没有提到每个单独的写入是否是原子的。虽然当前的实现可以确保每次调用都Write在下一次调用开始之前完全发生,但语言规范中并不能保证。


查看完整回答
反对 回复 2022-01-17
?
ABOUTYOU

TA贡献1812条经验 获得超5个赞

这个答案意味着写入是原子的。

io.Write 接口的具体实现者需要在发生部分写入时返回错误。net.Conn 在 unix 上通过获取锁并在循环中调用 write 来处理这个问题,直到整个缓冲区都被写入。在 Windows 上,它调用 WSASend,它保证发送整个缓冲区,除非发生错误。但是文档确实有这个警告

对 WSASend 的调用顺序也是缓冲区传输到传输层的顺序。WSASend 不应该在同一个面向流的套接字上同时从不同的线程调用,因为一些 Winsock 提供者可能会将一个大的发送请求分成多个传输,这可能会导致来自同一个面向流的多个并发发送请求的意外数据交错插座。

这意味着它不一定是原子的,除非 Go 获得了一个互斥体——它确实做到了

所以基本上它在实践中是原子的。可以想象,一个实现可以将线程安全定义为不崩溃,并通过解锁调用 write 周围的互斥锁(或在 Windows 上根本不获取它)来允许交错写入。但这对我来说没有意义,而且开发人员清楚地表明了相反的意图。


查看完整回答
反对 回复 2022-01-17
  • 2 回答
  • 0 关注
  • 157 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信