`

聊聊 tornado 的异步回调

阅读更多

异步回调程序的原理和写法我不就不介绍了,因为我主要是来吐槽下这种代码风格的。

 

最近因为追求性能所以去看了下tornado,然后发现这货如果你要利用它的高性能 ,那么你就要写回调代码,跟twisted一样,各种callback。

 

我们正常的同步代码一般是这样的

 

 

res = db.query(...)
res2 = dosomething(res)
res3 = db.insert(...)
return res3

 

 

 

上面的代码共四行,2次数据库操作,一次数据处理最后返回想要的结果。逻辑很清晰也很易懂,我想大部分的程序都是这样的。但如如果是异步的写法就会这么写

 

 

db.query(...,callback=fun2)

def fun2(res):
    res2 = dosomething(res,callback=fun3)

def fun3(res):
    db.insert(...,callback=fun4)

 

 

异步的代码就是只要你涉及到阻塞的代码就需要使用回调,呵呵,看到了吧2次阻塞就要求你把一段代码写成3段,代码易读性直线下降,如果你只是做一些简单的功能,代码也不多,我觉得还是能接受的,毕竟性能真的好,但是如果你要做一个很大的项目,一个请求可能要做4,5次阻塞操作,不敢想象,简直就是个灾难。

 

不过好在tornado还给了我们另一条活路,那就是tornado.gen http://www.tornadoweb.org/documentation/gen.html。

 

简单点说就是gen 给了我们用同步代码来做异步实现的可能。

 

我们来看看gen和普通异步代码。

class BaseHandler(tornado.web.RequestHandler):
    @property
    def db(self):
        if not hasattr(self, "_db"):
            self._db = asyncmongo.Client(pool_id='test_pool', **settings.get('mongo_database'))
        return self._db
    
    def api_response(self, data):
        """将数据转成json返回给客户端"""
        self.set_header("Content-Type", "application/json; charset=UTF-8")
        data = dumps(data)
        self.finish(data)

class A(BaseHandler):
    """
    同步代码实现异步
    """
    @tornado.web.asynchronous
    @gen.engine
    def get(self):
        res = self.get_user()
          
    @tornado.web.asynchronous
    @gen.engine
    def get_user(self):
        user_id = 'asdf'+str(random.randrange(1,490000)) #随机产生一个数据库里有的用户
        res = yield gen.Task(self.db.user.find,{'name':user_id},limit=1)
        res=res[0][0][0]
        self.api_response(res)
        
class B(BaseHandler):
    """
    异步代码
    """
    @tornado.web.asynchronous
    def get(self):
        user_id = 'asdf'+str(random.randrange(1,490000))#随机产生一个数据库里有的用户
        self.db.user.find({ 'name': user_id }, callback=self.async_callback(self.finish_save))
    
    def finish_save(self, response, error):
        self.api_response(response[0])

 

最后的最后我分别测试了2中写法最后在性能上的结果,我用ab -n 10000 -c 200  做了测试

 

gen 的代码 用了7秒

普通的异步代码  用了6.3秒

 

我觉得gen 略慢吧,但还是在可接受范围内,毕竟我不用写你妹的回调了。。。。怨念

 

 

当然 如果大家不是写web 就直接用gevent 吧,连这些gen的装饰器都可以省了。

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics