I just realised that WebSocketHandler.write_message()
returns a Future. I have not been yielding this function in my functions before:
@tornado.gen.coroutine
def ff(self,msg):
try:
self.write_message(json.dumps(msg))
except tornado.websocket.WebSocketClosedError:
pass
as opposed to:
@tornado.gen.coroutine
def ff(self,msg):
try:
yield self.write_message(json.dumps(msg))
except tornado.websocket.WebSocketClosedError:
pass
Why has this been working without an error? (running on Tornado 4.3)
Also for the design pattern:
for x in messages:
yield self.write_message(x)
would it be advisable to replace with a parallel?:
yield [self.write_message(x) for x in messages]
** Parallel WebSocketHandler wanting to send the same message to lots of websockets:
# WS is a list of WebSocketHandlers.
yield [s.write_message(message) for s in WS]
The Future
returned by write_message
is for flow control: it normally returns immediately, but when outgoing buffers reach a certain size it will wait until earlier messages have been sent. This slows the application down to match the network instead of allowing it to add more and more messages to the outgoing buffer.
These Futures
should not be yielded in parallel: it defeats the purpose, and I don't think it would even work reliably: each call to IOStream.write
invalidates the Future
returned by the previous call.
If you're not writing a large volume of messages, you can ignore these Futures
, but if you want to better control the amount of memory your application consumes, yield them one at a time.