猿问

tornado 3.2附带的chatdemo的代码中是如何实现异步的?最小利用cpu资源的,我没看见它释放cpu资源。

主程序的代码是:
#!/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.
importlogging
importtornado.auth
importtornado.escape
importtornado.ioloop
importtornado.web
importos.path
importuuid
fromtornadoimportgen
fromtornado.optionsimportdefine,options,parse_command_line
define("port",default=8888,help="runonthegivenport",type=int)
classMessageBuffer(object):
def__init__(self):
self.waiters=set()
self.cache=[]
self.cache_size=200
defwait_for_messages(self,callback,cursor=None):
ifcursor:
new_count=0
formsginreversed(self.cache):
ifmsg["id"]==cursor:
break
new_count+=1
ifnew_count:
callback(self.cache[-new_count:])
return
self.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:returnNone
returntornado.escape.json_decode(user_json)
classMainHandler(BaseHandler):
@tornado.web.authenticated
defget(self):
self.render("index.html",messages=global_message_buffer.cache)
classMessageNewHandler(BaseHandler):
@tornado.web.authenticated
defpost(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.asynchronous
defpost(self):
cursor=self.get_argument("cursor",None)
global_message_buffer.wait_for_messages(self.on_new_messages,
cursor=cursor)
defon_new_messages(self,messages):
#Closedclientconnection
ifself.request.connection.stream.closed():
return
self.finish(dict(messages=messages))
defon_connection_close(self):
global_message_buffer.cancel_wait(self.on_new_messages)
classAuthLoginHandler(BaseHandler,tornado.auth.GoogleMixin):
@gen.coroutine
defget(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("/")
return
self.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的理解不够深刻,也许二楼回答的就是对的。先采纳吧。谢谢大家的回答。
幕布斯7119047
浏览 291回答 2
2回答

桃花长相依

鉴于你竟然说到它看上去占用了很多服务器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()方法)。
随时随地看视频慕课网APP

相关分类

JavaScript
我要回答