英文:
In Go, does it make sense to write non-blocking code?
问题
从Node.js的角度来看,所有的代码都是非阻塞的。
在Go语言中,可以很容易地使用通道来实现非阻塞。
如果有人想在Go语言中编写一个类似于Node.js的服务器,将其设计为非阻塞的是否有意义?例如,让数据库的connect()函数返回一个通道,而不是在等待连接时阻塞。
对我来说,这似乎是正确的方法。
但是...
英文:
coming from node.js point of view, where all code is non-blocking.
In Go, non-blocking is easily achieved using channels.
if one were writing a node.js type server in go, does it make sense to make it non-blocking? for example, having a database connect() function return a channel, as versus blocking while waiting for the connection to occur.
to me, this seems the correct approach
but ...
答案1
得分: 79
阻塞和非阻塞并不是关于性能的问题,而是关于接口的问题。
如果你只有一个执行线程,那么阻塞调用会阻止你的程序在等待期间执行任何有用的工作。
但是如果你有多个执行线程,阻塞调用并不重要,因为你可以让该线程阻塞,同时在另一个线程中执行有用的工作。
在Go语言中,当goroutine在I/O上阻塞时,它会被另一个goroutine替换。Go运行时使用非阻塞的I/O系统调用,以避免操作系统阻塞线程,这样在第一个goroutine等待I/O时可以在其上运行不同的goroutine。
Goroutines非常廉价,因此不需要编写非阻塞式代码。
英文:
Blocking and non-blocking aren't really about performance, they are about an interface.
If you have a single thread of execution then a blocking call prevents your program from doing any useful work while it's waiting.
But if you have multiple threads of execution a blocking call doesn't really matter because you can just leave that thread blocked and do useful work in another.
In Go, a goroutine is swapped out for another one when it blocks on I/O. The Go runtime uses non-blocking I/O syscalls to avoid the operating system blocking the thread so a different goroutine can be run on it while the first is waiting for it's I/O.
Goroutines are really cheap so writing non-blocking style code is not needed.
答案2
得分: 32
编写阻塞函数。该语言允许您轻松地将同步调用转换为异步调用。
如果您想异步调用一个函数,请使用go语句。类似这样:
c := make(chan bool)
go func() {
阻塞函数()
c <- true
}()
// 在阻塞函数运行时做一些其他事情
// 如果阻塞函数尚未完成,则等待其完成
<-c
英文:
Write blocking functions. The language allows you to easily turn a synchronous call into an asynchronous one.
If you want to call a function asynchronously, use a go statement. Something like this:
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
答案3
得分: 22
在Go语言中,系统调用以非阻塞的方式实现,使用操作系统支持的最高效的底层机制(例如epoll
)。如果在等待调用结果时没有其他代码可运行,那么它会阻塞线程(因为没有更好的事情可做),但如果有其他活动的goroutine,则它们将会运行。
回调函数(就像你在js中使用的那样)本质上允许使用相同的底层机制,但对于程序员来说可能需要更多的思维运算。
在Go语言中,你可以在函数调用之后立即指定要运行的代码,而不是将其定义为回调函数。你希望与执行路径并行运行的代码应该包装在一个goroutine中,并通过通道进行通信。
英文:
In Go, system calls are implemented in a non-blocking way using the most efficient underlying mechanism that the OS supports (e.g. epoll
). If you have no other code to run while you wait for the result of a call, then it blocks the thread (for lack of a better thing to do), but if you have alternate goroutines active, then they will run instead.
Callbacks (as you're used to using in js) allow for essentially the same underlying mechanics, but with arguably more mental gymnastics necessary for the programmer.
In Go, your code to run after a function call is specified immediately following the function call rather than defined as a callback. Code that you want to run parallel to an execution path should be wrapped in a goroutine, with communication through channels.
答案4
得分: 12
对于典型的Web服务器类型应用程序,我建议不要将所有内容都异步化。有几个原因。
-
与异步代码相比,串行阻塞代码更容易理解(更容易发现错误)。
-
Golang的错误处理基于defer(),panic()和recover(),这可能无法完全满足您对100%异步代码的需求。
-
如果不小心处理,Goroutines可能会泄漏[一个讨论]。您拥有的异步行为越多,追踪此类问题就越困难,出现这类问题的可能性也越大。
一种策略是在高层次上专注于异步性,并将其他所有内容保持阻塞。因此,您可能会有一个“数据库处理程序”块,它在逻辑上与“请求处理程序”块不同。它们都在单独的goroutines中运行,并使用通道进行通信。但在“数据库处理程序”中,建立数据库连接和执行每个查询的调用是阻塞的。
您不必选择100%异步或0%异步。
英文:
For typical web-server type applications, I would recommend not making everything asynchronous. There are a few reasons.
-
It's easier to reason about serial blocking code than async code (easier to see bugs)
-
golang error handling is based on defer(), panic(), and recover(), which probably won't give you what you want with 100% asynchronous code
-
Goroutines can leak if you're not careful [one discussion]. The more async behavior you have, the harder it becomes to track down these types of problems and the more likely they are to show up.
One strategy is to focus the asynchonicity at a high level and leave everything else blocking. So you might have a "database handler" blob that is logically distinct from the "request handler" blob. They both run in separate goroutines and communicate using channels. But within the "database handler", the calls to establish a database connection and execute each query are blocking.
You don't have to choose 100% asynchronous or 0% asynchronous.
答案5
得分: 9
阻塞接口总是比非阻塞接口更简单和更好。Go的美妙之处在于它允许你以一种简单、易于理解的阻塞风格编写并发(和并行)代码。
非阻塞编程的流行是由于人们使用的语言(尤其是JavaScript)的不足,而不是因为非阻塞编程本质上更好。
英文:
Blocking interfaces are always simpler and better than non-blocking ones. The beauty of Go is that it allows you to write concurrent (and parallel) code in a simple, and easy to reason about, blocking style.
The fashion for non-blocking programming is all due to deficiencies in the languages people are using (specially JavaScript), not because non-blocking programming is intrinsically better.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论