Search code examples
goconcurrencycpu-usagegoroutine

goroutines have high idle wake up calls


I'm using GoLang to run two websocket clients (one for private and one for public data) simultaneously using goroutines. On the surface, everything seems to work fine. Both clients receive data transmitted from the websocket server. I believe I may have set something up wrong, however, since when I check activity monitor, my program consistently has between 500 - 1500 Idle Wake Ups and is using >200% of my CPU. This doesn't seem normal for something as simple as two websocket clients.

I've put the code in snippets so there's less to read (hopefully that makes it easier to understand), but if you need the entire code, I can post that as well. Here is the code in my main func that runs the ws clients

comms := make(chan os.Signal, 1)
signal.Notify(comms, os.Interrupt, syscall.SIGTERM)
ctx := context.Background()
ctx, cancel := context.WithCancel(ctx)
var wg sync.WaitGroup

wg.Add(1)
go pubSocket.PubListen(ctx, &wg, &activeSubs, testing)
wg.Add(1)
go privSocket.PrivListen(ctx, &wg, &activeSubs, testing)

<- comms
cancel()
wg.Wait()

Here is the code for how the clients run the go routines

func (socket *Socket) PubListen(ctx context.Context, wg *sync.WaitGroup, subManager *ConnStatus, testing bool) {
    defer wg.Done()
    for {
        select {
        case <- ctx.Done():
            log.Println("closing public socket")
            socket.Close()
            return
        default:
            socket.OnTextMessage = func(message string, socket Socket) {
                log.Println(message)
                pubJsonDecoder(message, testing)
                //tradesParser(message);
            }
        }
    }
}

func (socket *Socket) PrivListen(ctx context.Context, wg *sync.WaitGroup, subManager *ConnStatus, testing bool) {
    defer wg.Done()
    for {
        select {
        case <- ctx.Done():
            log.Println("closing private socket")
            socket.Close()
            return
        default:
            socket.OnTextMessage = func(message string, socket Socket) {
                log.Println(message)
            }
        }
    }
}

Any ideas on why the Idle Wake Ups are so high? Should I be using multithreading instead of concurrency? Thanks in advance for any help!


Solution

  • You're wasting CPU here (superfluous loop):

      for {
           // ...
            default:
            // High CPU usage here.
            }
        }
    

    Try something like this:

     func (socket *Socket) PubListen(ctx context.Context, wg *sync.WaitGroup, subManager *ConnStatus, testing bool) {
        defer wg.Done()
        defer socket.Close()
    
        socket.OnTextMessage = func(message string, socket Socket) {
            log.Println(message)
            pubJsonDecoder(message, testing)
            //tradesParser(message);
        }
    
        <-ctx.Done()
        log.Println("closing public socket")
    }
    
    func (socket *Socket) PrivListen(ctx context.Context, wg *sync.WaitGroup, subManager *ConnStatus, testing bool) {
        defer wg.Done()
        defer socket.Close()
    
        socket.OnTextMessage = func(message string, socket Socket) {
            log.Println(message)
        }
    
        <-ctx.Done()
        log.Println("closing private socket")
    }
    

    Also this may help:
    https://github.com/gorilla/websocket/blob/master/examples/chat/client.go