Alternative to a go routine per connection?

1,452 views
Skip to first unread message

Rajiv Kurian

unread,
Aug 30, 2013, 5:01:49 PM8/30/13
to golan...@googlegroups.com
Is it possible to have a single go routine handle multiple connections similar to how an epoll run loop would work. 

Thanks,
Rajiv

Rodrigo Kochenburger

unread,
Aug 30, 2013, 5:22:21 PM8/30/13
to Rajiv Kurian, golan...@googlegroups.com
Not really but keep in mind that go routine does not suffer of the same problem of a common threading model. Goroutines are much lighter then threads and they not map 1:1 to threads.

Doing what you say means there would need to be a callback oriented API, which is something off from the language design/philosophy.

Someone can correct me if I'm wrong but you can easily run hundreds of thousands of concurrent goroutines without problem, the only limitation is your system memory.

Hope this helps.

Cheers

- RK


--
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.

Ian Lance Taylor

unread,
Aug 30, 2013, 5:34:30 PM8/30/13
to Rajiv Kurian, golang-nuts
On Fri, Aug 30, 2013 at 2:01 PM, Rajiv Kurian <geet...@gmail.com> wrote:
> Is it possible to have a single go routine handle multiple connections
> similar to how an epoll run loop would work.

You could have a small goroutine for each connection feeding the data
into a channel, and then have one main goroutine that uses a loop
around a select statement. I don't know why you would want to do it
that way, but it should work.

Ian

Rajiv Kurian

unread,
Aug 30, 2013, 5:37:31 PM8/30/13
to golan...@googlegroups.com, Rajiv Kurian
Thanks for replying Rodrigo. I understand that go routines are not as heavy weight as a thread. However I am still interested in using a single go routine so as to save memory and context switching between go routines.

Epoll based apis don't need to be callback oriented. You can do something like this (psuedo code)

thread 1

while (1) {
 int n
 n = epoll_wait(...)
 for i := 0; i < n;  i++ {
    .....
    .....
    if its time to read {
       read all the data that you want to into a ring buffer.
    }
  }
}

thread 2 
  while (1) {
   read data from the ring buffer and process it.
  }
}

I was hoping that I could write to a global ring buffer from one go routine and then use a worker routine(s) to process the data. I would use channels to synchronize and establish a happens before relationship.

Rajiv Kurian

unread,
Aug 30, 2013, 5:39:55 PM8/30/13
to golan...@googlegroups.com, Rajiv Kurian
My motivation is to use a single go routine and lock it to a thread and save memory compared to the go routine per connection model.

Ian Lance Taylor

unread,
Aug 30, 2013, 5:48:07 PM8/30/13
to Rajiv Kurian, golang-nuts
On Fri, Aug 30, 2013 at 2:39 PM, Rajiv Kurian <geet...@gmail.com> wrote:
> My motivation is to use a single go routine and lock it to a thread and save
> memory compared to the go routine per connection model.

In that case, the answer is no.

But unless you want to run on some sort of small embedded system it's
not worth worrying about.

Ian

> On Friday, August 30, 2013 2:34:30 PM UTC-7, Ian Lance Taylor wrote:
>>
>> On Fri, Aug 30, 2013 at 2:01 PM, Rajiv Kurian <geet...@gmail.com> wrote:
>> > Is it possible to have a single go routine handle multiple connections
>> > similar to how an epoll run loop would work.
>>
>> You could have a small goroutine for each connection feeding the data
>> into a channel, and then have one main goroutine that uses a loop
>> around a select statement. I don't know why you would want to do it
>> that way, but it should work.
>>
>> Ian
>

Rajiv Kurian

unread,
Aug 30, 2013, 6:06:53 PM8/30/13
to golan...@googlegroups.com, Rajiv Kurian
I see. Thanks Ian.

Patrick Higgins

unread,
Aug 30, 2013, 6:53:43 PM8/30/13
to golan...@googlegroups.com, Rajiv Kurian
I tried to do something like this a year ago. I started with a very simple Go program that used one goroutine per connection and it worked well, but couldn't scale to 1M connections like I wanted it to (IIRC, it could handle 100k). I then decided to write a proxy in C which used epoll to multiplex 1M connections onto a smaller number of connections to my Go program, which was a simple modification of the original. Debugging that C program turned out to be so much harder than writing the original Go program that I finally became convinced that such designs simply aren't worth the maintenance cost.

Dave Cheney

unread,
Aug 30, 2013, 7:12:47 PM8/30/13
to Patrick Higgins, golan...@googlegroups.com, Rajiv Kurian
Years ago == go 1.0 or earlier? If so, I think you'll find your server can handle many more connections with 1.1 or later. 


Patrick Higgins

unread,
Aug 30, 2013, 10:19:57 PM8/30/13
to golan...@googlegroups.com, Rajiv Kurian
It was August 2012, and I was using tip. I just tried it out again
because I now have access to a perf testing environment with lots of
servers and memory, but ulimit -n hard limit is just 4096. :-( I'll
have to wait until next week to beg someone to raise that for me.

I remember trying with tip shortly before Go 1.1 came out and the
program had some strange errors that I didn't have time to
investigate. Hopefully I won't see those, but if I do I will report
them.

Dmitry Vyukov

unread,
Aug 31, 2013, 3:24:42 AM8/31/13
to Patrick Higgins, golang-nuts, Rajiv Kurian
On Sat, Aug 31, 2013 at 2:53 AM, Patrick Higgins
<patrick.al...@gmail.com> wrote:
> I tried to do something like this a year ago. I started with a very simple
> Go program that used one goroutine per connection and it worked well, but
> couldn't scale to 1M connections like I wanted it to (IIRC, it could handle
> 100k).

What exactly was the problem with 1M? Memory consumption?
It worths an issue on the tracker.

Patrick Higgins

unread,
Aug 31, 2013, 8:27:30 AM8/31/13
to Dmitry Vyukov, golang-nuts, Rajiv Kurian
It was just memory. I was running the program on two laptops, one with
4GB or RAM and the other with 8GB. Ultimately, I realized that between
socket buffers and the memory my program needed to process each
connection, the extra overhead of goroutine stacks is reasonable,
especially given how much easier they make writing a correct,
easy-to-read program.

Carlos Castillo

unread,
Aug 31, 2013, 10:49:33 PM8/31/13
to golan...@googlegroups.com, Rajiv Kurian
Rewrite http://golang.org/src/pkg/net/http/server.go?s=45668:45714#L1528, it's where the logic you fear is.

Carlos Castillo

unread,
Aug 31, 2013, 11:21:26 PM8/31/13
to golan...@googlegroups.com, Rajiv Kurian
Please Note: I don't suggest you rewite the stdlib unless absolutely necessary.

AFAIK, go has an O(1) scheduler, so the number of goroutines in the system doesn't affect scheduling speed. Also, if you are starting a new goroutine (and waiting for it to be scheduled), you are performing as many context switches (1) as sending a value down a channel to a thread pool.

Rajiv Kurian

unread,
Sep 1, 2013, 11:44:53 AM9/1/13
to golan...@googlegroups.com
Thanks Carlos. I couldn't rewrite HTTP without the support of TCP connections that support what I want. I only need TCP and not HTTP. My main motivation was to save memory.

Dmitry Vyukov

unread,
Sep 2, 2013, 1:01:03 AM9/2/13
to Rajiv Kurian, golang-nuts
Well, I guess theoretically it's possible to use
syscall.EpollCtl/EpollWait/Read/Write. It's strongly discouraged, but
should work.


On Sun, Sep 1, 2013 at 7:44 PM, Rajiv Kurian <geet...@gmail.com> wrote:
> Thanks Carlos. I couldn't rewrite HTTP without the support of TCP connections that support what I want. I only need TCP and not HTTP. My main motivation was to save memory.
>

Rajiv Kurian

unread,
Sep 2, 2013, 2:15:56 PM9/2/13
to golan...@googlegroups.com, Rajiv Kurian
Yeah like you said Dmitry, this is strongly discouraged. I'll either change the architecture or try to prototype in C/C++ or Java NIO. Go's decision to use a go routine per connection makes perfect sense. As a trade-off it makes programming much much simpler at a slight cost in memory. I wouldn't want to bend the language against it's design.
Reply all
Reply to author
Forward
0 new messages