-1

I'd like to have a TCP connection for a gaming application. It's important to be time efficient. I want to receive many objects efficiently. It's also important to be CPU efficient because of the load.

So far, I can make sure handleConnection is called every time a connection is dialed using go's net library. However once the connection is created, I have to poll (check over and over again to see if new data is ready on the connection). This seems inefficient. I don't want to run that check to see if new data is ready if it's needlessly sucking up CPU.

I was looking for something such as the following two options but didn't find what I was looking for.

(1) Do a read operation that somehow blocks (without sucking CPU) and then unblocks when new stuff is ready on the connection stream. I could not find that.

(2) Do an async approach where a function is called when new data arrives on the connection stream (not just when a new connection is dialed). I could not find that.

I don't want to put any sleep calls in here because that will increase the latency of responding to singles messages.

I also considered dialing out for every single message, but I'm not sure if that's efficient or not.

So I came up with code below, but it's still doing a whole lot of checking for new data with the Decode(p) call, which does not seem optimal.

How can I do this more efficiently?

func handleConnection(conn net.Conn) {
        dec := gob.NewDecoder(conn)
        p := &P{}

        for {
                result := dec.Decode(p)
                if result != nil {
                        // do nothing
                } else {
                        fmt.Printf("Received : %+v", p)
                        fmt.Println("result", result, "\n")
                }

        }

        conn.Close()
}
Rick Giuly
  • 983
  • 1
  • 14
  • 19
  • Redialing for every message is almost certainly the least efficient option. I'm not sure what you mean "it's still doing a whole lot of checking for new data with the Decode(p) call" - it will read until it gets a whole object, then return. It's not repeatedly polling or anything. – Adrian Aug 01 '17 at 21:06
  • As far as your two options - (1) all read calls block without using CPU, and (2) not sure what you mean "I could not find that", you'd have to write your code as you described. – Adrian Aug 01 '17 at 21:08
  • Sorry posted wrong code, now it should demonstrate the problem. Note that the connection is just open forever and it's waiting for objects to arrive. When there's nothing available, the err results tells me. When something is available, then it gets read. However it's always checking over and over to see if something is available. – Rick Giuly Aug 01 '17 at 23:15
  • What is the measured performance of your code? Have you actually observed a problem, or are you trying to solve a hypothetical? – Adrian Aug 01 '17 at 23:23

1 Answers1

0

You say:

So I came up with code below, but it's still doing a whole lot of checking for new data with the Decode(p) call.

Why do you think that? The gob decoder will issue a Read to the conn and wait for it to return data before figuring out what it is and decoding it. This is a blocking operation, and will be handled asynchronously by the runtime behind the scenes. The goroutine will sleep until the appropriate io signal comes in. You should not have to do anything fancy to make that more performant.

You can trace this yourself in the code for decoder.Decode.

I think your code will work just fine. CPU will be idle until it receives more data.

Go is not node. Every api is "blocking" for the most part, but that is not as much as a problem as in other platforms. The runtime manages goroutines very efficiently and delegates appropriate signals to sleeping goroutines as needed.

captncraig
  • 22,118
  • 17
  • 108
  • 151
  • Sorry posted wrong code. Now it should demonstrate the issue. I can't just break out when an object is received because I want the connection to stay open. So what I'm doing (with updated code to what I meant to post) is running Decode a lot to check if there's another object ready to read. Decode doesn't really block. It just returns an EOF if there's nothing new ready to read. – Rick Giuly Aug 01 '17 at 23:19
  • How long does it take to return EOF? Do you ever get valid data after that? EOF usually means the connection closed. – captncraig Aug 02 '17 at 00:35
  • Actually it looks like Decode does in fact block. I must have had a brain fart at some point and accidentally closed the connection after sending each object or something. This explains everything. Should be fine now. – Rick Giuly Aug 02 '17 at 00:49