主程序的代码是:#!/usr/bin/envpython##Copyright2009Facebook##LicensedundertheApacheLicense,Version2.0(the"License");youmay#notusethisfileexceptincompliancewiththeLicense.Youmayobtain#acopyoftheLicenseat##http://www.apache.org/licenses/LICENSE-2.0##Unlessrequiredbyapplicablelaworagreedtoinwriting,software#distributedundertheLicenseisdistributedonan"ASIS"BASIS,WITHOUT#WARRANTIESORCONDITIONSOFANYKIND,eitherexpressorimplied.Seethe#Licenseforthespecificlanguagegoverningpermissionsandlimitations#undertheLicense.importloggingimporttornado.authimporttornado.escapeimporttornado.ioloopimporttornado.webimportos.pathimportuuidfromtornadoimportgenfromtornado.optionsimportdefine,options,parse_command_linedefine("port",default=8888,help="runonthegivenport",type=int)classMessageBuffer(object):def__init__(self):self.waiters=set()self.cache=[]self.cache_size=200defwait_for_messages(self,callback,cursor=None):ifcursor:new_count=0formsginreversed(self.cache):ifmsg["id"]==cursor:breaknew_count+=1ifnew_count:callback(self.cache[-new_count:])returnself.waiters.add(callback)defcancel_wait(self,callback):self.waiters.remove(callback)defnew_messages(self,messages):logging.info("Sendingnewmessageto%rlisteners",len(self.waiters))forcallbackinself.waiters:try:callback(messages)except:logging.error("Errorinwaitercallback",exc_info=True)self.waiters=set()self.cache.extend(messages)iflen(self.cache)>self.cache_size:self.cache=self.cache[-self.cache_size:]#Makingthisanon-singletonisleftasanexerciseforthereader.global_message_buffer=MessageBuffer()classBaseHandler(tornado.web.RequestHandler):defget_current_user(self):user_json=self.get_secure_cookie("chatdemo_user")ifnotuser_json:returnNonereturntornado.escape.json_decode(user_json)classMainHandler(BaseHandler):@tornado.web.authenticateddefget(self):self.render("index.html",messages=global_message_buffer.cache)classMessageNewHandler(BaseHandler):@tornado.web.authenticateddefpost(self):message={"id":str(uuid.uuid4()),"from":self.current_user["first_name"],"body":self.get_argument("body"),}#to_basestringisnecessaryforPython3'sjsonencoder,#whichdoesn'tacceptbytestrings.message["html"]=tornado.escape.to_basestring(self.render_string("message.html",message=message))ifself.get_argument("next",None):self.redirect(self.get_argument("next"))else:self.write(message)global_message_buffer.new_messages([message])classMessageUpdatesHandler(BaseHandler):@tornado.web.authenticated@tornado.web.asynchronousdefpost(self):cursor=self.get_argument("cursor",None)global_message_buffer.wait_for_messages(self.on_new_messages,cursor=cursor)defon_new_messages(self,messages):#Closedclientconnectionifself.request.connection.stream.closed():returnself.finish(dict(messages=messages))defon_connection_close(self):global_message_buffer.cancel_wait(self.on_new_messages)classAuthLoginHandler(BaseHandler,tornado.auth.GoogleMixin):@gen.coroutinedefget(self):ifself.get_argument("openid.mode",None):user=yieldself.get_authenticated_user()self.set_secure_cookie("chatdemo_user",tornado.escape.json_encode(user))self.redirect("/")returnself.authenticate_redirect(ax_attrs=["name"])classAuthLogoutHandler(BaseHandler):defget(self):self.clear_cookie("chatdemo_user")self.write("Youarenowloggedout")defmain():parse_command_line()app=tornado.web.Application([(r"/",MainHandler),(r"/auth/login",AuthLoginHandler),(r"/auth/logout",AuthLogoutHandler),(r"/a/message/new",MessageNewHandler),(r"/a/message/updates",MessageUpdatesHandler),],cookie_secret="__TODO:_GENERATE_YOUR_OWN_RANDOM_VALUE_HERE__",login_url="/auth/login",template_path=os.path.join(os.path.dirname(__file__),"templates"),static_path=os.path.join(os.path.dirname(__file__),"static"),xsrf_cookies=True,)app.listen(options.port)tornado.ioloop.IOLoop.instance().start()if__name__=="__main__":main()主要是classMessageUpdatesHandler(BaseHandler)那里,明明是用了异步的装饰器,但是我没看出来他是如何把他做成异步的,如果没有做成异步的,那这个东西会占用服务器的cpu的资源太多了,我想官方安装包下的demo应该不会出错的,请哪位大神帮我细致的解释一下,这段demo是如何唯美地实现了一个chatroom的功能?(其实它的大致意思我大概是能理解的,就是没发现他是如何在这个问题上用异步的,明明用了异步的装饰器,但是就是没有发现它使如何用异步的)————————————注:我理解异步,理解他这个chat的实现思路,只是认为他想做成异步的,但似乎实现异步的过程中是错的,没有用到异步,因为onnewmessage那里虽然用到了异步装饰器,但是没有用到异步。求指出他在具体哪一步释放cpu线程的。对于二楼提出的他构造了一个异步的function的callback,但是callback回调函数不是异步的特有函数,是很平常的函数构造,我没看出他的构造。而我知道把异步的东西分开来构造的是func(args,callback=(yieldgen.Callback(key)))result=yieldgen.Wait(key)虽然说他没有gen,但是他根本没有用到他自己导入的那个tornado.web.asynchronous模块的任何功能。所以说感觉上他就没有实现异步。其实这个问题的最佳实践方法是websocket,不过我就是觉得除了websocket的另外一个官方的直接不用websocket的代码应该不会有问题,明明用了异步装饰器,但是却没有发现他用到异步的功能。所以疑问。—————————————不过可能是我对tornado的理解不够深刻,也许二楼回答的就是对的。先采纳吧。谢谢大家的回答。
2 回答
桃花长相依
TA贡献1860条经验 获得超8个赞
鉴于你竟然说到它看上去占用了很多服务器CPU资源,那么我假设你其实并不知道异步是什么。什么是同步编程?举个例子。你去快餐店买快餐,店员问你要什么,然后他等着你回答。你说你要X、Y、Z,并且付款,然后你等着店员把食物取给你。什么是异步编程?还是举个例子。你去一餐馆吃饭。服务器过去了,递给你菜单,然后去忙其它事情了。等你们把菜点好,你们通知服务器菜点好了,他们把菜单收过去处理。在这段时间你们可以做其它的事情,聊天啊玩手机之类的。你们看到菜上上来了,于是你们开始就餐。在网络编程中,与科学计算和数据处理等非常不同的一点是,你没有很多需要大量CPU计算的任务,但是你会经常等待用户把请求发过来,以及等待响应发送到用户端。同步编程就是配备很多服务员,每个服务员处理完一个顾客才会去处理下一个顾客的需求。而异步编程,「有事叫我」——classMessageUpdatesHandler(BaseHandler):@tornado.web.authenticated@tornado.web.asynchronousdefpost(self):cursor=self.get_argument("cursor",None)global_message_buffer.wait_for_messages(self.on_new_messages,cursor=cursor)defon_new_messages(self,messages):#Closedclientconnectionifself.request.connection.stream.closed():returnself.finish(dict(messages=messages))defon_connection_close(self):global_message_buffer.cancel_wait(self.on_new_messages)global_message_buffer.wait_for_messages(self.on_new_messages,cursor=cursor)这句即是说,有消息来了就去调用self.on_new_messages函数。没消息的时候程序就做其它的事情去了。比如用户的消息还没来,但是来了一个新的请求,于是程序请处理这个新的请求,直到它结束或者类似地等待某个事件发生。至于那个@tornado.web.asynchronous,它的意思是告诉Tornado框架,这位服务员会在顾客暂时不需要服务时离开,暂时离开并不代表服务已经完毕(即函数返回时不要认为请求已经完成从而清理之),并且会在请求处理完毕之后告诉Tornado(即调用self.finish()方法)。
添加回答
举报
0/150
提交
取消