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

Goroutine I/O 调度

Goroutine I/O 调度

Go
料青山看我应如是 2021-10-25 20:22:34
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 堆栈?
查看完整描述

2 回答

?
蛊毒传说

TA贡献1895条经验 获得超3个赞

您可以查看文件https://github.com/golang/go/blob/master/src/net/fd_unix.go(写入函数)。

基本上,这取决于套接字缓冲区是否有足够的空间。

如果套接字缓冲区中有足够的空间来容纳您的写操作的大小,数据将立即写入套接字缓冲区。我想这对应于您的第二个答案。此外,内核实际上可能会发送数据包(或将其添加到 NIC 队列),但它独立于 Go 运行时。

如果套接字缓冲区中没有足够的空间来容纳整个写入操作,则只会立即将部分数据写入套接字缓冲区。然后,调用将阻塞(通过运行时轮询引擎),直到内核在套接字缓冲区中留出一些空间(通过发送一些数据包)。只要有一些空间可用,并且所有数据都已复制,呼叫就会解除阻塞。

您应该考虑在 net 包通过系统调用将整个缓冲区写入套接字缓冲区时采用的时间戳。


查看完整回答
反对 回复 2021-10-25
?
慕姐4208626

TA贡献1852条经验 获得超7个赞

在下面的文章介绍了netpoller是如何工作的:

每当 goroutine 尝试读取或写入连接时,网络代码将执行操作,直到收到此类错误,然后调用 netpoller,告诉它在准备再次执行 I/O 时通知 goroutine。然后 goroutine 被调度到它正在运行的线程之外,另一个 goroutine 在它的位置运行。

当 netpoller 收到来自 OS 的通知,它可以对文件描述符执行 I/O 时,它会查看其内部数据结构,查看是否有任何 goroutine 在该文件上被阻塞,如果有,则通知它们。然后 goroutine 可以重试导致它阻塞的 I/O 操作并成功执行此操作。”

因此我们得出结论,只要底层系统调用完成对整个缓冲区的写入,就可以重新调度 goroutine。在 Linux 的情况下,当消息被复制到内核空间发送缓冲区时似乎是蜜蜂:阻塞套接字:确切地说,“send()”何时返回?. 这又是我的第二个原始选项“当缓冲区被复制到运行时和操作系统的内核空间时”。

查看完整回答
反对 回复 2021-10-25
  • 2 回答
  • 0 关注
  • 224 浏览
慕课专栏
更多

添加回答

举报

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