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

时间:2016-06-20 12:37:19

标签: multithreading networking go goroutine

我的节目是这样的:

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将向同一连接发送消息。 我怀疑服务器是否会收到错误消息,例如&#34; hellohelloworldworld&#34;,但是当程序在我的Ubuntu 14.04LTS中运行时没有问题。

那么,多个goroutine会同时在Conn上调用一个方法吗?

=============================================== ==========================

如何保持Write方法的原子性?

2 个答案:

答案 0 :(得分:4)

文档说明:

  

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

没有提到每个单独的写是否是原子的。虽然当前的实现可以确保在下一次调用开始之前完成对Write的每次调用,但是在语言规范中无法保证。

答案 1 :(得分:0)

answer 表示写入是原子的。

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

<块引用>

调用 WSASend 的顺序也是调用 WSASend 的顺序 缓冲区被传输到传输层。 WSASend 不应该是 从不同的并发调用同一个面向流的套接字 线程,因为某些 Winsock 提供程序可能会拆分大型发送请求 多次传输,这可能会导致意外数据 从多个并发发送请求交错 面向流的套接字。

这意味着它不一定是原子的,除非 Go 获得互斥锁 - which it does

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