1 回答
TA贡献1848条经验 获得超10个赞
也许不是完整的解决方案,但只是一些想法..
第一个好的改变是,他们的客户(服务员)是一个 set() ,它确保默认情况下每个客户只包含一次。它作为类变量进行定义和访问。因此,您不使用 self.waiters 而是使用 cls.waiters 或 ClassName.waiters (在本例中为 ChatSocketHandler.waiters)来访问它。
class ChatSocketHandler(tornado.websocket.WebSocketHandler): waiters = set()
第二个变化是它们以 @classmethod 的形式更新每个客户端(您可以在此处选择将更新发送给部分客户端而不是全部客户端),因为它们不想接收实例(self)而是类(cls)并引用类变量(在本例中为 waiter、cache 和 cach_size)
我们可以在这里忘记缓存和缓存大小。
像这样:
@classmethod
def send_updates(cls, chat):
logging.info("sending message to %d waiters", len(cls.waiters))
for waiter in cls.waiters:
try:
waiter.write_message(chat)
except:
logging.error("Error sending message", exc_info=True)
每次 API 调用时,都会创建处理程序的新实例,称为self
. 并且中的每个参数self
对于实例来说都是唯一的,并且与调用您的方法的实际客户端相关。这有助于在每次通话时识别客户。因此,基于实例的客户端列表(如 (self.clients))在每次调用时始终为空。添加客户端只会将其添加到该实例的世界视图中。
但有时您希望一些变量(例如客户端列表)对于从您的类创建的所有实例都相同。这就是类变量(直接在类定义下定义的变量)和@classmethod
装饰器发挥作用的地方。
@classmethod
使方法调用独立于实例。这意味着您只能访问这些方法中的类变量。但对于消息代理来说,这正是我们想要的:
将客户端添加到类变量中,该变量对于处理程序的所有实例都是相同的。由于它被定义为一个集合,因此每个客户端都是唯一的。
接收消息时,将其发送给所有(或一部分客户端)
so
on_message
是一个“正常”实例方法,但它调用类似:最后send_updates()
是 a 。@classmethod
send_updates() 迭代所有(或子集)客户端(服务员)并最终使用它来发送实际更新。
从例子来看:
@classmethod
def send_updates(cls, chat):
logging.info("sending message to %d waiters", len(cls.waiters))
for waiter in cls.waiters:
try:
waiter.write_message(chat)
except:
logging.error("Error sending message", exc_info=True)
请记住,您使用 waiters.append(self) 添加了服务员,因此每个服务员实际上都是一个实例,并且您“简单地”调用实例(该实例代表调用者) write_message() 方法。所以这不是广播,而是一一发送给每一个来电者。您可以在此处按某些标准(例如主题或组)进行分隔...
简而言之:用于@classmethod独立于特定实例(例如您的情况下的调用者或客户端)的方法,并且您希望对“所有”或“所有”客户端的子集执行操作。但您只能在这些方法中访问类变量。这应该没问题,因为这是他们的目的;)
添加回答
举报