来自node.js的观点,其中所有代码都是非阻塞的。
在Go中,使用频道可以轻松实现非阻塞。
如果有人在go中编写node.js类型的服务器,是否有意义使其无阻塞?例如,让数据库connect()函数返回一个通道,而不是在等待连接发生时阻塞。
对我来说,这似乎是正确的方法但......
答案 0 :(得分:64)
阻塞和非阻塞并不是关于性能,而是关于接口。 如果你有一个执行线程,那么阻塞调用会阻止你的程序在等待时做任何有用的工作。 但是如果你有多个执行线程,阻塞调用并不重要,因为你可以让那个线程被阻塞并在另一个线程中做有用的工作。
在Go中,当goroutine在I / O上阻塞时,会换掉另一个goroutine。 Go运行时使用非阻塞I / O系统调用来避免操作系统阻塞线程,以便在第一个等待它的I / O时可以在其上运行不同的goroutine。
Goroutines非常便宜,因此不需要编写非阻塞样式代码。
答案 1 :(得分:25)
写阻塞功能。该语言允许您轻松地将同步调用转换为异步调用。
如果要异步调用函数,请使用go语句。像这样:
c := make(chan bool)
go func() {
blockingFunction()
c <- true
}()
// do some other stuff here while the blocking function runs
// wait for the blocking function to finish if it hasn't already
<-c
答案 2 :(得分:18)
在Go中,使用操作系统支持的最有效的底层机制(例如epoll
)以非阻塞方式实现系统调用。如果在等待调用结果时没有其他代码可以运行,那么它会阻塞线程(因为没有更好的事情可做),但是如果你有替代goroutines处于活动状态,那么它们将会运行。
回调(因为你习惯于在js中使用)允许基本上相同的底层机制,但可以说程序员需要更多的心理体操。
在Go中,在函数调用之后立即指定要在函数调用之后运行的代码,而不是将其定义为回调。您希望与执行路径并行运行的代码应该包含在goroutine中,并通过通道进行通信。
答案 3 :(得分:10)
对于典型的Web服务器类型的应用程序,我建议不使一切都异步。有几个原因。
比异步代码更容易推理串行阻塞代码(更容易看到错误)
golang错误处理基于defer(),panic()和recover(),这可能无法为您提供100%异步代码所需的内容
如果您不小心[one discussion],Goroutines可能会泄漏。您拥有的异步行为越多,追踪这些类型的问题就越难以显示出来。
一种策略是将异步性集中在一个高水平,并让其他一切阻塞。因此,您可能有一个“数据库处理程序”blob,它在逻辑上与“请求处理程序”blob不同。它们都在不同的goroutine中运行并使用通道进行通信。但是在“数据库处理程序”中,建立数据库连接和执行每个查询的调用都是阻塞的。
您不必选择100%异步或0%异步。
答案 4 :(得分:6)
阻塞接口总是比非阻塞接口更简单,更好。 Go的优点在于它允许您以简单,易于推理的方式编写并发(和并行)代码,阻止样式。
非阻塞编程的时尚是由于人们使用的语言(特别是JavaScript)的不足,而不是因为非阻塞编程本质上更好。