goroutines提供了阻止I/O到goroutine (-programmer)的接口。在幕后,运行时自然使用某种非阻塞I/O来防止OS挂起OS -线程,以便运行时可以在执行I/O时在OS线程之上运行另一个goroutine。
运行时什么时候考虑执行I/O以便重新调度goroutine?
要说清楚的是,假设我有一个叫net.TCPConn
的Write
,什么时候可以重新安排时间呢?
conn, err := net.Dial("tcp", serverAddr)
conn.Write(buffer)
timestamp = time.Now()
那是什么时候,我可以期待的时间戳将采取?
发布于 2015-08-05 12:51:02
您可以查看文件unix.go (写函数)。
基本上,这取决于套接字缓冲区是否有足够的空间。
如果套接字缓冲区中有足够的空间来容纳写入操作的大小,数据将立即写入套接字缓冲区。我想这是你的第二个答案。此外,内核可能实际上发送数据包(或将其添加到NIC队列),但它与Go运行时无关。
如果套接字缓冲区中没有足够的空间来容纳整个写操作,则只会将部分数据立即写入套接字缓冲区。然后,调用将阻塞(通过运行时轮询引擎),直到内核在套接字缓冲区中留出一些空间(通过发送一些数据包)。一旦有了一些可用的空间,并且所有的数据都被复制了,调用就会解除阻塞。
当网络包通过系统调用在套接字缓冲区中写入整个缓冲区时,您应该考虑使用时间戳。
发布于 2015-08-05 13:15:18
下列条款描述了netpoller的工作方式:
每当一个goroutine尝试读取或写入连接时,网络代码都会执行该操作,直到它收到这样的错误,然后调用netpoller,告诉它准备好再次执行I/O时通知它。然后,从它正在运行的线程中调度出goroutine,然后在它的位置上运行另一个goroutine。 当netpoller从操作系统收到可以对文件描述符执行I/O的通知时,它将查看它的内部数据结构,查看该文件上是否有阻塞的goroutines,并通知它们是否存在。然后,goroutine可以重试I/O操作,从而阻止并成功地执行此操作。“
因此,我们得出结论,只要底层系统调用完成对整个缓冲区的写入,就可以重新调度goroutine。在Linux的情况下,当消息被复制到内核空间发送缓冲区:阻塞套接字:确切地说,"send()“何时返回?时,它似乎就会发生变化。这反过来又是我的第二个原始选项:“当缓冲区被复制到运行时和操作系统的内核空间时”;也符合迪迪埃·斯皮亚氏的答案。
https://stackoverflow.com/questions/31830814
复制相似问题