Live data from Hacker News

Evio – Fast event-loop networking for Go

github.com

31–40 of 67 posts

Re: Evio – Fast event-loop networking for Go

#31

Earlier quoted context omitted.

That is exactly what Go does by default. Any time a blocking operation is performed, Go either leaves the OS-level thread blocked there and switches away, or hand the blocking operation to an internal thread which is running epoll for the whole process. The end result is much easier than Python/NodeJs because there is no explicit "async/await" or deferred-style programming. You simply write linear code and any blocki…

Thanks for taking the time to write this response. The more I hear about Go's features, the more I seem to like it.

FYI, this is not unique to Go. A number of languages implement lightweight threads in the same way (roughly), like erlang or Haskell. It’s all epoll or other efficient polling primitives under the hood.

Re: Evio – Fast event-loop networking for Go

#32
post #8

One of my favorite things about Go is that it cuts through the "threads vs. events" debate by offering thread-style programming with event-style scaling using what you might call green threads (compiler assisted cooperative multitasking that has the programming semantics of preemptive multitasking). That is, I can write simple blocking code, and my server still scales. Using event loop programming in Go would take aw…

It doesn't really "cut through" the debate any more than any other implementation of threads does. The only difference between Go and plain old one-thread-per-connection is that regular threads run in the kernel, while Go threads run in userspace. That's not a semantic difference, only an implementation detail (a large detail, to be clear, but still an implementation detail).

There were historical implementations of pthreads, such as NGPT, that used precisely the same model as Go, and they were abandoned because the advantages over 1:1 were not sufficient to justify the complexity.

Re: Evio – Fast event-loop networking for Go

#33

Earlier quoted context omitted.

That is, I can write simple blocking code, and my server still scales. Using event loop programming in Go would take away one of my favorite things about the language, so I won't be using this. If Go has or can emulate 'generators' a-la Python/Nodejs,then you can write synchronous looking,blocking-like code with event loops as well.

That is exactly what Go does by default. Any time a blocking operation is performed, Go either leaves the OS-level thread blocked there and switches away, or hand the blocking operation to an internal thread which is running epoll for the whole process. The end result is much easier than Python/NodeJs because there is no explicit "async/await" or deferred-style programming. You simply write linear code and any blocki…

In other words, Go uses threads.

There's nothing semantically unique to Go about this model.

Re: Evio – Fast event-loop networking for Go

#34

At this point, why not just use C++? I feel like people are trying to stretch Go way past what it's good for. It's not going to replace C++ where C++ is effective, and it shouldn't :)

Because memory safety is much easier to achieve in Go than in C++, even "modern C++".

Re: Evio – Fast event-loop networking for Go

#35
post #8

One of my favorite things about Go is that it cuts through the "threads vs. events" debate by offering thread-style programming with event-style scaling using what you might call green threads (compiler assisted cooperative multitasking that has the programming semantics of preemptive multitasking). That is, I can write simple blocking code, and my server still scales. Using event loop programming in Go would take aw…

It doesn't really "cut through" the debate any more than any other implementation of threads does. The only difference between Go and plain old one-thread-per-connection is that regular threads run in the kernel, while Go threads run in userspace. That's not a semantic difference, only an implementation detail (a large detail, to be clear, but still an implementation detail). There were historical implementations of…

The goroutine implementation scales, while other thread implementations (by default) do not. That's a semantic difference. A Go server can have millions of active goroutines with moderate resource use.

You can achieve the same on Linux or Solaris using kernel threads, but you have to work at it. With Go you don't have to work at it, and it works on macOS and Windows and a few other OSs too.

This is all comparisons between O(1) things, but the constant factor matters.

Re: Evio – Fast event-loop networking for Go

#36
post #25
post #22

Earlier quoted context omitted.

> It's for building specialized services such as key value stores, L7 proxies, static websites, etc. First of all, thank you for publishing this project. It's very interesting in my opinion since I never thought about the benefits of an event loop. Would you mind explaining briefly why an event loop is a better suit for these applications? Is it due to performance and efficiency?

I'd suggest that's not the right way to look at it. To a first approximation, "everything" is using an event loop nowadays, in that everything is using the same fundamental primitives to handle and dispatch events. In particular, this includes the Go runtime; run "strace" on a Go network program and you'll see these same calls pop up in the strace. What this does instead is give a Go program direct access to the even…

> It does seem to me that a lot of people are a bit bedazzled by the top-level stuff that various languages offer, and forget that under the hood, everyone's using the event-based interfaces.

Yup. It's all very similar under the hood.

The most important difference between I/O models is whether the paradigm involves explicit vs. implicit management of the event loop. Callback models like Node, async/await style models like those of C#, and low-level primitives like IOCP, epoll, and kqueue fall into the former category. Go/Erlang, plain old threads, and even Unix processes fall into the latter category. There are advantages and disadvantages of each model.

Within each of these broad categories, the distinctions are, IMHO, much less interesting, and they're often made out to be more significant than they actually are. In particular, the distinction between runtimes like Go and regular OS pthreads is often made out to be more important than it really is, when the difference ultimately boils down to the CPU privilege level that thread management runs at.

Re: Evio – Fast event-loop networking for Go

#37

Earlier quoted context omitted.

It doesn't really "cut through" the debate any more than any other implementation of threads does. The only difference between Go and plain old one-thread-per-connection is that regular threads run in the kernel, while Go threads run in userspace. That's not a semantic difference, only an implementation detail (a large detail, to be clear, but still an implementation detail). There were historical implementations of…

The goroutine implementation scales, while other thread implementations (by default) do not. That's a semantic difference. A Go server can have millions of active goroutines with moderate resource use. You can achieve the same on Linux or Solaris using kernel threads, but you have to work at it. With Go you don't have to work at it, and it works on macOS and Windows and a few other OSs too. This is all comparisons be…

> You can achieve the same on Linux or Solaris using kernel threads, but you have to work at it.

By setting the thread stack size to a reasonable value. That's it. And, in fact, on 64-bit you often don't even need to do that.

The difference you're describing is a difference in default thread stack sizes, which is hardly a paradigm shift. We're talking about one call to pthread_attr_setstacksize().

Re: Evio – Fast event-loop networking for Go

#38

Earlier quoted context omitted.

That is exactly what Go does by default. Any time a blocking operation is performed, Go either leaves the OS-level thread blocked there and switches away, or hand the blocking operation to an internal thread which is running epoll for the whole process. The end result is much easier than Python/NodeJs because there is no explicit "async/await" or deferred-style programming. You simply write linear code and any blocki…

In other words, Go uses threads. There's nothing semantically unique to Go about this model.

Go uses an m:n thread model. Goroutines are multiplexed onto a smaller number of os-level threads. They're sort of like threads, but they have a simplified programming model (There is no thread-level storage for example).

Re: Evio – Fast event-loop networking for Go

#39
post #38

Earlier quoted context omitted.

In other words, Go uses threads. There's nothing semantically unique to Go about this model.

Go uses an m:n thread model. Goroutines are multiplexed onto a smaller number of os-level threads. They're sort of like threads, but they have a simplified programming model (There is no thread-level storage for example).

Goroutines are threads. They're just not kernel-level threads.

There have been implementations of pthreads that used an M:N model, for instance.

Re: Evio – Fast event-loop networking for Go

#40
This is single-threaded? What are you going to do with the other 31 or 63 cores?

The single-threaded nature of applications liked Redis an Haproxy is a singificant impediment to their vertical scalability. CPUs aren't getting faster, we're just going to get more cores, so anything that assumes there's only a single core seems like a dead end.

Haproxy literally just added multithreading support in 1.8.

Post reply on HN