Tornado实现简单的异步
1.同步和异步的概念
**同步**
含义:指两个或两个以上随时间变化的量在变化过程中保持一定的相对关系
现象:有一个共同的时钟,按来的顺序一个一个处理
直观感受 :就是需要等候,效率低下
**异步**
含义 :双方不需要共同的时钟,也就是接收方不知道发送方什么时候发送,所以在发送的信息中就要有提示接收方开始接收的信息,如开始位,同时在结束时有停止位
现象:没有共同的时钟,不考虑顺序来了就处理
直观感受:就是不用等了,效率高
2.阻塞调用和非阻塞调用
*阻塞调用**
含义 : 阻塞调用是指调用结果返回之前,当前线程会被挂起(线程进入非可执行状态,在这个状态下,CPU不会给线程分配时间片,即线程暂停运行)。函数只有在得到结果之后才会返回。
现象:读套接字时没有数据等数据来,写套接字时写不下了也一直等,等能写下了往里写(套接字被写满的原因不在本地,在于网络另一头的套接字被写满了来不及读出去,导致本地的套接字内容来发不出去堵住了)
直观感受:执着
**非阻塞调用**
含义 :非阻塞调用是指没有调用结果立即返回,当前线程不被挂起,可以继续做其它工作
现象:读套接字时没有数据,不等直接返回干别的事去,写套接字写不下了也不写了,直接返回干别的事去
直观感受:勤奋
3.tornado的异步编程
**1.通过回调实现异步编程**
首先是我们来编写一个同步的代码:
import datetime import tornado.httpserver import tornado.ioloop import tornado.options import tornado.web from tornado.options import define,options from pycket.session import SessionMixin from data.user_modules import User,session define('port',default=8010,help='run port',type=int) class BaseHandler(tornado.web.RequestHandler,SessionMixin): def get_current_user(self): # current_user = self.get_secure_cookie('ID') current_user = self.session.get('user') if current_user: return current_user return None class AbcHandler(BaseHandler): def get(self): """测试路由""" self.write('ok') class SyncHandler(BaseHandler): def get(self): """同步代码""" client = tornado.httpclient.HTTPClient() response = client.fetch("http://127.0.0.1:8000/sync?id=3") self.write(response.body) if __name__ == '__main__': tornado.options.parse_command_line() app = tornado.web.Application( handlers=[ (r'/abc',AbcHandler), (r'/sync',SyncHandler), ], template_path='templates', static_path='static', debug=True, ) app.db = {} http_server = tornado.httpserver.HTTPServer(app) http_server.listen(options.port) tornado.ioloop.IOLoop.instance().start()
我们新启一个服务,然后去请求我们之前启的另一个服务,另外一个服务有休眠,我们用次来模拟程序的阻塞。
当请求`sync`这个的路由的时候,发生阻塞,应为tornado是单线程的,所以这个时候去请求`abc`这个路由的时候也会发生阻塞。因此,我们需要使用异步来帮助我们避免阻塞,使用异步的方式有多种,我们接下来分别来看一下。
**使用回调函数来实现异步**
# 导入模块 import tornado.httpclient class CallbackHandler(BaseHandler): """通过回调函数来实现异步""" @tornado.web.asynchronous def get(self): client = tornado.httpclient.AsyncHTTPClient() # 异步的方法 client.fetch("http://127.0.0.1:8000/sync?id=2",callback=self.on_response) self.write('Ok!'+'<br>') def on_response(self,response): print(response) self.write(response.body) self.finish() # 必须要加上
**通过协程实现异步**
# 导入模块 import tornado.gen class GenHandler(BaseHandler): """通过协程实现的异步""" @tornado.web.asynchronous @tornado.gen.coroutine # coroutine 协程 def get(self): client = tornado.httpclient.AsyncHTTPClient() response = yield tornado.gen.Task(client.fetch,"http://127.0.0.1:8000/sync?id=3") print(response) self.write(response.body)
**通过协程实现异步(自定义函数)**
class FuncHandler(BaseHandler): """通过协程实现的异步""" @tornado.web.asynchronous @tornado.gen.coroutine # coroutine 协程 def get(self): response = yield self.func() print(response) self.write(response.body) @tornado.gen.coroutine def func(self): #此处的函数只是简单的演示,可以为复杂的逻辑进行实现 各个功能 client = tornado.httpclient.AsyncHTTPClient() response = yield tornado.gen.Task(client.fetch,"http://127.0.0.1:8000/sync?id=4") raise tornado.gen.Return(response)
**通过协程来实现异步(使用requests模块)**
# 首先安装模块 # pip install futures # pip install requests # 导入模块 from tornado.concurrent import run_on_executor from concurrent.futures import ThreadPoolExecutor import requests class MyFuncHandler(BaseHandler): """通过协程实现的异步""" executor = ThreadPoolExecutor() @tornado.web.asynchronous @tornado.gen.coroutine # coroutine 协程 def get(self): response = yield self.func() print(response) self.write(response.text) @run_on_executor def func(self): response = requests.get("http://127.0.0.1:8000/sync?id=4") return response
以上的这些实现异步的方式大家都是可以使用的,也需要熟练掌握。
**总结**
因为tornado是单线程的,所以在路由层如果发生阻塞,那么 整个服务器的会因此无法访问,为了避免这种事情的发生,我们采用异步的这种方式来避免。
在tornado中实现异步的方式多样的,大家需要记住上面给出的几种方式,并且能够熟练使用。
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
到此tornado的基础部分已经基本完成,这些基础知识会在之后的项目中用到,持续更新中.......
                    
                
                
            
        
浙公网安备 33010602011771号