try to reduce redundant goroutines

This commit is contained in:
Shivaram Lingamneni 2018-04-15 19:05:22 -04:00
parent 4778e7bcc7
commit f54561171e
1 changed files with 26 additions and 12 deletions

View File

@ -59,7 +59,7 @@ func (socket *Socket) Close() {
socket.closed = true socket.closed = true
socket.Unlock() socket.Unlock()
go socket.send() socket.wakeWriter()
} }
// CertFP returns the fingerprint of the certificate provided by the client. // CertFP returns the fingerprint of the certificate provided by the client.
@ -134,10 +134,22 @@ func (socket *Socket) Write(data string) (err error) {
} }
socket.Unlock() socket.Unlock()
go socket.send() socket.wakeWriter()
return return
} }
// wakeWriter starts the goroutine that actually performs the write, without blocking
func (socket *Socket) wakeWriter() {
// attempt to acquire the trylock
select {
case <-socket.writerSlotOpen:
// acquired the trylock; send() will release it
go socket.send()
default:
// failed to acquire; the holder will check for more data after releasing it
}
}
// SetFinalData sets the final data to send when the SocketWriter closes. // SetFinalData sets the final data to send when the SocketWriter closes.
func (socket *Socket) SetFinalData(data string) { func (socket *Socket) SetFinalData(data string) {
socket.Lock() socket.Lock()
@ -163,19 +175,21 @@ func (socket *Socket) readyToWrite() bool {
// send actually writes messages to socket.Conn; it may block // send actually writes messages to socket.Conn; it may block
func (socket *Socket) send() { func (socket *Socket) send() {
for { for {
select { // we are holding the trylock: actually do the write
case <-socket.writerSlotOpen:
// got the trylock: actually do the write
socket.performWrite() socket.performWrite()
// surrender the trylock: // surrender the trylock, avoiding a race where a write comes in after we've
// checked readyToWrite() and it returned false, but while we still hold the trylock:
socket.writerSlotOpen <- true socket.writerSlotOpen <- true
// check if more data came in while we held the trylock: // check if more data came in while we held the trylock:
if !socket.readyToWrite() { if !socket.readyToWrite() {
return return
} }
select {
case <-socket.writerSlotOpen:
// got the trylock, loop back around and write
default: default:
// someone else has the trylock; if there's more data to write, // failed to acquire; exit and wait for the holder to observe readyToWrite()
// they'll see if after they release it // after releasing it
return return
} }
} }