猿问

Goroutine I/O 调度

Golangs goroutines 为 goroutine (-programmer) 提供了一个阻塞 I/O 的接口。在幕后,运行时自然会使用某种非阻塞 I/O 来防止 OS 挂起 OS 线程,以便运行时可以在执行 I/O 时在 OS 线程之上运行另一个 goroutine。


运行时什么时候考虑执行的 I/O 以便它可以重新调度 goroutine?


明确地说,假设我有一个net.TCPConn我调用的,我Write什么时候可以期望重新安排 goroutine?


conn, err := net.Dial("tcp", serverAddr)

conn.Write(buffer)

timestamp = time.Now()

那是什么时候我可以期望使用时间戳?

  • 当缓冲区被复制到 golang 运行时?

  • 何时将缓冲区复制到运行时和操作系统的内核空间?

  • 当缓冲区被复制到运行时、内核空间以及网卡的发送缓冲区时?

  • 缓冲区何时通过网络/从 NIC 发送?

  • 当缓冲区已被接收端确认时,TCP 堆栈?


料青山看我应如是
浏览 225回答 2
2回答

蛊毒传说

您可以查看文件https://github.com/golang/go/blob/master/src/net/fd_unix.go(写入函数)。基本上,这取决于套接字缓冲区是否有足够的空间。如果套接字缓冲区中有足够的空间来容纳您的写操作的大小,数据将立即写入套接字缓冲区。我想这对应于您的第二个答案。此外,内核实际上可能会发送数据包(或将其添加到 NIC 队列),但它独立于 Go 运行时。如果套接字缓冲区中没有足够的空间来容纳整个写入操作,则只会立即将部分数据写入套接字缓冲区。然后,调用将阻塞(通过运行时轮询引擎),直到内核在套接字缓冲区中留出一些空间(通过发送一些数据包)。只要有一些空间可用,并且所有数据都已复制,呼叫就会解除阻塞。您应该考虑在 net 包通过系统调用将整个缓冲区写入套接字缓冲区时采用的时间戳。

慕姐4208626

在下面的文章介绍了netpoller是如何工作的:每当 goroutine 尝试读取或写入连接时,网络代码将执行操作,直到收到此类错误,然后调用 netpoller,告诉它在准备再次执行 I/O 时通知 goroutine。然后 goroutine 被调度到它正在运行的线程之外,另一个 goroutine 在它的位置运行。当 netpoller 收到来自 OS 的通知,它可以对文件描述符执行 I/O 时,它会查看其内部数据结构,查看是否有任何 goroutine 在该文件上被阻塞,如果有,则通知它们。然后 goroutine 可以重试导致它阻塞的 I/O 操作并成功执行此操作。”因此我们得出结论,只要底层系统调用完成对整个缓冲区的写入,就可以重新调度 goroutine。在 Linux 的情况下,当消息被复制到内核空间发送缓冲区时似乎是蜜蜂:阻塞套接字:确切地说,“send()”何时返回?. 这又是我的第二个原始选项“当缓冲区被复制到运行时和操作系统的内核空间时”。
随时随地看视频慕课网APP

相关分类

Go
我要回答