英文:
Channels in Go, and emitters in node.js?
问题
Go语言有没有类似于node.js的"emitter"的功能?
我正在通过将我写的一个node.js库移植到Go来学习Go语言。在node.js版本中,该库在某些事件发生时会发出一个事件(例如,它监听UDP端口1234,当接收到"ABC"时,会发出"abcreceived"事件,以便调用代码可以根据需要做出响应(例如,发送"DEF")。
我在Go语言中看到了通道(channel)的用法(并且正在阅读相关资料),但由于我对这门语言还不太熟悉,我不知道是否可以(或者如何)使用通道与使用我的库的代码进行通信。
我还看到了https://github.com/chuckpreslar/emission,但不确定这是否可行,或者是否有更好("最佳实践")的方法来实现这些功能。
英文:
Does Go have an equivalent of node.js' "emitter"?
I'm teaching myself Go by porting over a node.js library I wrote. In the node version, the library emits an event once something happens (e.g. it listens on UDP port 1234 and when "ABC" is received, "abcreceived" is emitted so the calling code can respond as necessary (e.g. sending back "DEF")
I've seen channels in Go (and am currently reading up on them), but as I'm still new to this language, I don't know if (or how, for that matter) that can be used to communicate with whatever code is using my library.
I've also seen https://github.com/chuckpreslar/emission, but am not sure if this is acceptable, or if there's a better ("Best practice") way of doing things.
答案1
得分: 2
Go和Node.js非常不同。Node.js只支持通过回调函数实现并发。可能有各种各样的方式来装饰它们,但它们本质上都是回调函数。
在Node.js中,没有并行性;Node.js是单线程运行时。当使用Node.js的async
来实现所谓的“并行”执行时,它并不是Go中所使用的并行的意义上的并行,而是并发。
在Go中,有基于通信顺序进程(CSP)的显式并发,这是由牛津大学的Tony Hoare构思的数学基础。运行时通过将协作进程(称为goroutines)进行时间切片,交错地运行它们在可用的CPU核心上。在每个goroutine中,代码是单线程的,因此很容易编写。在简单的情况下,goroutines之间不共享数据;而是通过通道传递消息。这样,就不需要使用回调函数。
当goroutines因等待I/O而被阻塞时,这是可以接受的,因为它们在解除阻塞之前不会使用任何CPU时间。它们的内存占用很小,你可以拥有非常大量的goroutines。因此,对于I/O操作,也不需要回调函数。
由于Go和Node.js的执行模型差异非常大,尝试从一个平台移植代码到另一个平台很可能会导致非常笨拙的解决方案。最好从原始需求开始,从头开始实现。
通过使用函数参数来扭曲Go并发模型以模拟回调函数是一个不好的主意,因为这不符合惯用法,并且会失去CSP所带来的好处。
英文:
Go and Node.js are very different. Node.js supports concurrency only via callbacks. There might be various ways of dressing them up, but they're fundamentally callbacks.
In Node.js, there is no parallelism; Node.js has a single-threaded runtime. When Node.js async
is used to achieve what is called 'parallel' execution, it isn't parallel in the sense used in Go, but concurrent.
Concurrency is not parallelism in the Go world.
Go has explicit concurrency based on Communicating Sequential Processes (CSP), a mathematical basis conceived by Tony Hoare at Oxford. The runtime interleaves cooperating processes called goroutines by time-slicing them onto the available CPU cores. Within each goroutine, the code is single threaded, so is easy to write. In the simple case, no data is shared between goroutines; instead messages pass between them along channels. In this way, there is no need for callbacks.
When goroutines get blocked waiting for I/O, that's OK because they don't use any CPU time until they're unblocked. Their memory footprint is slight and you can have very large numbers of them. So callbacks are not needed for I/O operations either.
Because the execution models of Go and Node.js are about as different as they could be, attempting to port code from one to the other is very likely to lead to very clumsy solutions. It's better to start from the original requirements and implement from scratch.
It would be possible to distort the Go concurrency model using function arguments to behave like callbacks. This would be a bad idea because it would not be idiomatic and would lose the benefits that CSP gives.
答案2
得分: 1
通过阅读他人的Go代码和评论中的一些链接,我认为通道是解决问题的方法。
在我的库代码中(半伪代码):
// 创建一个名为"Events"的新通道
var Events = make(chan
func doSomething() {
// ...
Events <- "abcreceived" // 将"abcreceived"添加到Events通道中
}
在将使用我的库的代码中:
evt := <-mylib.Events
switch evt {
case "abcreceived":
sendBackDEF()
break
// ...
}
我仍然更喜欢Node.js的EventEmitter(因为可以轻松地传输数据),但对于简单的事情,这应该足够了。
英文:
So by reading others' Go code and some links in the comments to my question, I think channels are the way to go.
In my library code (semi pseudo-code):
// Make a new channel called "Events"
var Events = make(chan
func doSomething() {
// ...
Events <-"abcreceived" // Add "abcreceived" to the Events channel
}
And in the code that will use my library:
evt := <-mylib.Events
switch evt {
case "abcreceived":
sendBackDEF()
break
// ...
}
I still prefer node.js' EventEmitter (because you can transfer data back easily) but for simple things, this should suffice.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论