Re: [go-nuts] What does Go provide for efficient asynchronous IO programming ?

7,279 views
Skip to first unread message

Jan Mercl

unread,
Apr 27, 2013, 7:08:25 AM4/27/13
to Christophe Meessen, golang-nuts

What apparent lack of support for asynchronous IO you're talking about?

Just do IO in a separate goroutine(s).

-j

On Apr 27, 2013 1:03 PM, "Christophe Meessen" <christoph...@gmail.com> wrote:
As I red in the documentation Go is designed for SMP processing :
  with blocking IO and threads communicating through channels.

Asynchronous IO is known empirically to be more efficient (see nignx for instance).
So I would like to know what does Go provide to support asynchronous IO ?
Let say something like libev using non blocking IO.

The efficiency difference depends of course on the type of application and the dependency of threads.
While I'm very pleased by the language simplicity, but the apparent lack of support for asynchronous IO is not attractive.

I would expect that Go could be as fast as the JVM machines in this benchmark
http://www.techempower.com/benchmarks/#section=data-r3
My feeling is that the first requirement to aim this objective would be support asynchronous IO.





--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Dave Cheney

unread,
Apr 27, 2013, 7:17:30 AM4/27/13
to Christophe Meessen, golang-nuts
Go provides non blocking socket io via the net package, is this what
you are referring to with the comparison to nginx ?

Go does not support Asynchronous IO, AIO, does any operating system
support it well ? I know linux users kernel threads to simulate it.

On Sat, Apr 27, 2013 at 8:37 PM, Christophe Meessen

Andreas Krennmair

unread,
Apr 27, 2013, 7:19:23 AM4/27/13
to Christophe Meessen, golan...@googlegroups.com
What you perceive as synchronous I/O actually isn't. The runtime transparently handles that for you. Go combines the best of both worlds: efficient I/O and no callback hell.

Regards,
Andreas

Jonathan Amsterdam

unread,
Apr 27, 2013, 10:48:02 AM4/27/13
to golan...@googlegroups.com
Christophe,
I think what you are missing is that a goroutine is not the same as a thread. The Go runtime multiplexes goroutines across a small number of OS threads. It also is able to keep the initial stack size of a goroutine small (4K), while allowing it to grow dynamically if necessary. These two things together mean that you can have thousands or millions of goroutines in your program. The Go runtime scheduler will efficiently switch among them. Internally, I believe it uses epoll or other asynchronous, select-based mechanisms to handle I/O. So as Andreas said, you get the best of both worlds.

Tad Glines

unread,
Apr 27, 2013, 11:41:03 AM4/27/13
to golan...@googlegroups.com
The goroutine is really light weight. A context switch, on my system, takes about 400 nanoseconds.

In this (https://github.com/ericmoritz/wsdemo/blob/results-v1/results.md) C10K performance test, go came in a close second behind Erlang.

A C/C++ AIO based implementation will probably outperform any other implementation, so if performance is the most important metric, then just stick with C. But, if you are willing to sacrifice a few percentage points on IO performance, then you can probably get the same implementation in fewer lines of code and it will be easier to read and maintain. 


Dave Cheney

unread,
Apr 27, 2013, 7:17:55 PM4/27/13
to Christophe Meessen, Christophe Meessen, golang-nuts
That is exactly what the net package provides.



On 28/04/2013, at 4:19 AM, Christophe Meessen <chris...@meessen.net> wrote:

> We need non blocking sockets and epoll, a very efficient select. The goal is to beeing able to have a single thread handle all IO operations.
>
> --
> Ch.Meessen

Christophe Meessen

unread,
Apr 27, 2013, 2:19:29 PM4/27/13
to Dave Cheney, Christophe Meessen, golang-nuts
We need non blocking sockets and epoll, a very efficient select. The goal is to beeing able to have a single thread handle all IO operations.

--
Ch.Meessen

Le 27 avr. 2013 à 13:17, Dave Cheney <da...@cheney.net> a écrit :

Christophe Meessen

unread,
Apr 27, 2013, 2:15:37 PM4/27/13
to Andreas Krennmair, Christophe Meessen, golan...@googlegroups.com
Could you be more explicit on why what I perceive as synchonous IO actualy isn't ? 
Fully agree that callbacks is a hell, but when performance is critical, and the tasks not too complex, it may be worth the effort. 

I guess a benchmark is needed to objectively determine the performance difference of the two approches, if any, and in what type of usage scenario the difference becomes significant.

Communication between threads introduces an uncrontrollable latency that increases with the load of the host because we depend on the OS scheduler. A single threaded app does it's own IO processing scheduling by hand and without any need for thread synchronization. This is why it's more efficient I guess.

--
Ch.Meessen

Andreas Krennmair

unread,
Apr 27, 2013, 7:42:32 PM4/27/13
to Christophe Meessen, Christophe Meessen, golan...@googlegroups.com
On Sat, Apr 27, 2013 at 8:15 PM, Christophe Meessen <chris...@meessen.net> wrote:
Could you be more explicit on why what I perceive as synchonous IO actualy isn't ? 

Yes: you do a f.Read(). What happens in the background is that the runtime will really just epoll() (or kqueue() depending on your operating system) on that file descriptor, schedule other go routines while that's happening, and only return from the Read() when there is data to be read. So what you know from libev's event loop is really just baked into the language runtime and is a little bit more complex than a simple event loop. The code of the Go runtime might be a bit hard to understand, but a system that's conceptually practically the same and IMHO really easy to understand is rsc's libtask library: http://swtch.com/libtask/ It provides basically the same functionality, but for C on Unix.

 
Fully agree that callbacks is a hell, but when performance is critical, and the tasks not too complex, it may be worth the effort. 

As described in the previous paragraph, there is no need to manually separate your program into many small functions, the Go runtime knows when a read operation happens, suspend execution there and resume as soon as there's actual data to read, all completely transparent for the programmer.
 
Communication between threads introduces an uncrontrollable latency that increases with the load of the host because we depend on the OS scheduler. A single threaded app does it's own IO processing scheduling by hand and without any need for thread synchronization. This is why it's more efficient I guess.

The Go runtime will schedule many goroutines (as others in this thread mentioned, you can easily have tens to hundreds of thousand of goroutines in a program) on top of a single OS thread. Forget about OS threads when you think about goroutines, they don't really play a role. You can always run a program with many goroutines on a single OS thread, so all your assumptions about uncontrollable latency with increasing load and a dependency on the OS scheduler fall flat.

If you specifically want to compare nginx with any goroutine-based and network-I/O-heavy program: yes, probably nginx will be better in benchmarks (that's just a guess, I haven't measured it, but that's not my point), but that's only because nginx has been specifically optimized for doing exactly one thing well (serving HTTP), while the Go runtime abstracts several linear threads of executions (i.e. goroutines) onto an OS thread, including all the I/O scheduling. Go code will always be easier to read, easier to understand and easier to reason about exactly because of that, while still being reasonably efficient in execution speed.

Regards,
Andreas

Sébastien Paolacci

unread,
Apr 28, 2013, 4:15:41 AM4/28/13
to Christophe Meessen, Dave Cheney, Christophe Meessen, golang-nuts
Hello Christophe,

We need non blocking sockets and epoll, a very efficient select. (...)

As Dave (and few others) already mentioned, that's exactly what you already have (for free) with the Go runtime (e.g http://tip.golang.org/src/pkg/runtime/netpoll_epoll.c)

The only difference with the "traditional" async model is that the runtime takes care -for you- of waking-up the (very lightweight) goroutines when the awaited event occur.

What you see as a `blocking read' is actually a suspended goroutine that is waiting for the epollin (linux) event to be received by the `network poller' daemon.

In short, you're programming through a (sane) synchronous model a system that, under the hood, is backed by event based implementations (and thus by nasty concurrent callbacks hells). That's what a lot of people are referring to as "best of both world".

Sebastien

ps: if you want to run benchmarks, please use lastest Go 1.1 betas (or tip) since a lot of perf improvements were made over Go 1.0

Christophe Meessen

unread,
Apr 28, 2013, 5:15:55 AM4/28/13
to Andreas Krennmair, Christophe Meessen, golan...@googlegroups.com
Thank you very much Andreas for this clarification. Now I understand that Go routines are in fact coroutines/user space threads/fibers/greenlets equivalent but hidden under the hood of the language. I missed that information. Now Jan Mercl's answer to just use Go routines make sense to me!

I then fully agree on the mutual benefit on efficiency and code simplicity. Excellent design choice ! It makes Go even more exciting to work with.

Thank you to all the people who took the time to read my question and those who answered.
-- 
Bien cordialement,

Ch. Meessen

traetox

unread,
Apr 21, 2016, 10:14:12 AM4/21/16
to golang-nuts, akren...@gmail.com, christoph...@gmail.com, chris...@meessen.net
https://github.com/traetox/goaio

In case you are still interested in a kernel supported async file IO implementation.

Alex Bligh

unread,
Apr 21, 2016, 10:30:08 AM4/21/16
to traetox, Alex Bligh, golang-nuts, akren...@gmail.com, christoph...@gmail.com, chris...@meessen.net

On 21 Apr 2016, at 15:14, traetox <tra...@gmail.com> wrote:

> https://github.com/traetox/goaio
>
> In case you are still interested in a kernel supported async file IO implementation.

Interesting. Any chance of a Flush() method? I can do a trivial driver for
https://github.com/abligh/gonbdserver

--
Alex Bligh




Reply all
Reply to author
Forward
0 new messages