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

我的程序是这样的:


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方法的原子性?


Cats萌萌
浏览 158回答 2
2回答

PIPIONE

该文档指出:多个 goroutine 可以同时调用 Conn 上的方法。没有提到每个单独的写入是否是原子的。虽然当前的实现可以确保每次调用都Write在下一次调用开始之前完全发生,但语言规范中并不能保证。

ABOUTYOU

这个答案意味着写入是原子的。io.Write 接口的具体实现者需要在发生部分写入时返回错误。net.Conn 在 unix 上通过获取锁并在循环中调用 write 来处理这个问题,直到整个缓冲区都被写入。在 Windows 上,它调用 WSASend,它保证发送整个缓冲区,除非发生错误。但是文档确实有这个警告:对 WSASend 的调用顺序也是缓冲区传输到传输层的顺序。WSASend 不应该在同一个面向流的套接字上同时从不同的线程调用,因为一些 Winsock 提供者可能会将一个大的发送请求分成多个传输,这可能会导致来自同一个面向流的多个并发发送请求的意外数据交错插座。这意味着它不一定是原子的,除非 Go 获得了一个互斥体——它确实做到了。所以基本上它在实践中是原子的。可以想象,一个实现可以将线程安全定义为不崩溃,并通过解锁调用 write 周围的互斥锁(或在 Windows 上根本不获取它)来允许交错写入。但这对我来说没有意义,而且开发人员清楚地表明了相反的意图。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go