我正在使用带龙卷风的websockets。
一旦我收到一条消息(可以在下面的例子中“开始”和“停止”),start将每隔x秒轮询来自memcached的消息,并将json输出返回给websocket客户端。
我使用“tornado.ioloop.PeriodicCallback”每隔x秒轮询一次。所以我的问题是在这种情况下函数“poll_for_new_data”有阻塞代码,即memcached获取,json.dumps转换为json等。我如何处理这个阻塞代码,我认为当调用时阻塞主事件循环慢 ?如果您有不同设计的建议来处理这个问题,请告诉我。我打算使用线程池来阻塞功能,这是一个好主意(或)有更好的方法来做到这一点吗?
我必须为这个项目使用pylibmc(memcached客户端),因为它使用c ++ libmemcached来满足特定需求。我不能使用异步memcache库,除非它在引擎盖下使用c ++ libmemcached。
感谢您的时间
注意:我评论了我的CustomClass特定代码,因为我没有在这里共享代码。
from tornado import ioloop, websocket, httpserver, gen
import tornado
import json
# from custom_class import CustomClass
class CustomWebSocketHandler(tornado.websocket.WebSocketHandler):
def check_origin(self, origin):
# for CORS
print(origin)
return True
def open(self):
print("open " + self.get_argument("user"))
def on_message(self, message):
message = message.lower()
print("on_message: " + message)
if(message == "start"):
self.request = {"user": self.get_argument("user")}
#self.all_pids = set()
#self.custom_class = CustomClass(self.request)
# poll for data every x seconds
self.periodic_callback = tornado.ioloop.PeriodicCallback(
self.poll_for_new_data, 10 * 1000)
self.periodic_callback.start()
elif(message == "stop"):
self.close()
def on_close(self):
print("on_close")
self.periodic_callback.stop()
def poll_for_new_data(self):
if self.ws_connection is None:
return
# check for new pids
# [queries memcached servers using pylibmc (http://sendapatch.se/projects/pylibmc/) client]
# new_pids = self.custom_class.get_new_pids(self.all_pids)
# if(len(new_pids) > 0):
# if self.ws_connection is not None:
# self.write_message(json.dumps(new_pids))
# there is more code here which I did not include
# i.e. this function pools for process that register themselves
# and each process has messages. so every time this method is called
# we are looking for new PIDs and new messages for each PID
# sending the result to websocket client in JSON format
def make_app():
return tornado.web.Application([
(r'/ws', CustomWebSocketHandler)
])
if __name__ == "__main__":
app = make_app()
http_server = tornado.httpserver.HTTPServer(app)
http_server.listen(8888)
# http://tornadokevinlee.readthedocs.org/en/latest/ioloop.html
tornado.ioloop.IOLoop.current().start()
答案 0 :(得分:1)
一般情况下,我建议使用循环协程而不是PeriodicCallback:http://www.tornadoweb.org/en/stable/guide/coroutines.html#running-in-the-background
这样可以更容易地使用线程池来管理阻塞调用;只需使用yield thread_pool.submit(f)
。如果您尝试使用PeriodicCallback向线程池提交任务,那么确保超出不会导致多个请求并行运行可能会非常棘手。
答案 1 :(得分:0)
通常,将新的定期轮询器绑定到打开的每个websocket实例听起来是个坏主意。为什么不在服务器上实现单独的轮询器作为单独的工作进程,并让它在发生时发布更新。
您可以使用Redis的pubsub将每个websocket实例订阅到Redis频道,并在每次更新时从投票工作者发布。