我对Go如何处理非阻塞IO感到有些困惑。
API在我看来基本上是同步的,并且在Go上观看演示时,听到诸如"和调用块"之类的注释并不罕见。

从文件或网络读取时,Go是否使用阻塞IO?
还是在Go例程中使用某种魔术来重写代码?

来自C#背景,这感觉非常不直观,在C#中,当使用异步API时,我们使用await关键字。
这清楚地表明该API可以产生当前线程,并在以后的延续中继续。

所以TLDR;
在执行Go例程中的IO时,Go会阻塞当前线程吗,还是会使用延续将其转换为C#之类的异步等待状态机?

Go有一个调度程序,可让您编写同步代码,并自行进行上下文切换,并在后台使用异步IO。因此,如果您正在运行多个goroutine,则它们可能在单个系统线程上运行,并且当您的代码从goroutine的视图中阻止时,它实际上并没有被阻止。这不是魔术,但是的,它掩盖了您的所有这些东西。

调度程序将在需要它们时以及在真正阻塞的操作期间分配系统线程(例如,我认为文件IO正在阻塞或正在调用C代码)。但是,如果您正在做一些简单的http服务器,则实际上可以使用少数几个"真实线程"来拥有成千上万个goroutine。

您可以在此处阅读有关Go的内部原理的更多信息:

https://morsmachine.dk/go-scheduler

您应该先阅读@Not_a_Golfer答案以及他提供的链接,以了解goroutine的调度方式。我的答案更像是更深入地研究网络IO。我假设您了解Go如何实现协作式多任务处理。

Go可以并且确实仅使用阻塞调用,因为所有内容都在goroutines中运行,并且它们不是真正的OS线程。它们是绿色线程。因此,您可以让它们中的许多都阻塞IO调用,并且它们不会像OS线程那样消耗所有的内存和CPU。

文件IO只是系统调用。 Not_a_Golfer已经介绍了这一点。 Go将使用真实的OS线程来等待syscall,并且在goroutine返回时将取消阻塞。在这里,您可以看到Unix的文件read实现。

网络IO不同。运行时使用"网络轮询器"来确定应该从IO调用中取消阻止的goroutine。根据目标操作系统的不同,它将使用可用的异步API来等待网络IO事件。调用看起来像阻塞,但内部的所有操作都是异步完成的。

例如,当您首先在TCP套接字上调用read时,goroutine将尝试使用syscall进行读取。如果什么都没到达,它将阻塞并等待恢复。这里所说的阻塞是指停车,它将goroutine放入等待恢复的队列中。这就是使用网络IO时,"已阻止" goroutine使其他goroutine执行的方式。

https://golang.org/src/net/fd_unix.go?s=#L237

当数据到达时,网络轮询器将返回应恢复的goroutine。您可以在此处看到findrunnable函数,该函数搜索可以运行的goroutine。它调用netpoll函数,该函数将返回可以恢复的goroutine。您可以在此处找到netpollkqueue实现。

对于C#中的异步/等待。异步网络IO也将使用异步API(Windows上的IO完成端口)。当某些内容到达时,操作系统将在线程池的完成端口线程之一上执行回调,这将使当前SynchronizationContext继续执行。从某种意义上说,存在一些相似之处(停泊/取消停泊确实看起来像在调用连续性,但级别低得多),但是这些模型有很大的不同,更不用说实现了。默认情况下,goroutine未绑定到特定的OS线程,可以在其中任何一个线程上恢复它们??,没关系。没有UI线程要处理。专门进行异步/等待是为了使用SynchronizationContext恢复同一OS线程上的工作。而且因为没有绿色线程或单独的调度程序,异步/等待程序必须将您的函数拆分为多个在SynchronizationContext上执行的回调,这基本上是一个无限循环,用于检查应执行的回调队列。您甚至可以自己实现它,这真的很容易。

有些issuespull request可能对您有帮助:)

它也许可以解决诸如

之类的一些问题

  • golang何时会阻塞IO操作?
  • 为什么golang仅将async io用于socket而不是normal file

    https://github.com/golang/go/issues/18507
    https://github.com/golang/go/commit/c05b06a12d005f50e4776095a60d6bd9c2c91fac
    https://github.com/golang/go/issues/6222
    https://github.com/golang/go/issues/6817
    对常规文件进行Epoll