在Go中,编写非阻塞代码是否有意义?

时间:2011-06-13 09:29:26

标签: node.js go blocking

来自node.js的观点,其中所有代码都是非阻塞的。

在Go中,使用频道可以轻松实现非阻塞。

如果有人在go中编写node.js类型的服务器,是否有意义使其无阻塞?例如,让数据库connect()函数返回一个通道,而不是在等待连接发生时阻塞。

对我来说,这似乎是正确的方法

但......

5 个答案:

答案 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)的不足,而不是因为非阻塞编程本质上更好。