tornado异步编程与node.js异步编程

tornado是由FaceBook开源的一个异步python框架,node.js是由Joyent资助的开源项目,致力于提供一套编写高性能并发Web应用的JavaScript框架。这篇博客就简单谈一谈两种异步框架在Linux下的异同,若是有错误或者表达不恰当的地方欢迎各路大神指正。html

在Linux下,node.js靠libev和libeio配合使用来实现异步I/O。libev是一个事件驱动库,基于poll/epoll提供的I/O复用方式,主要用于事件驱动的网络编程。libeio是异步版的POSIX API,主要负责文件I/O操做,他仅仅依赖于pthread,能够和libev配合使用。libev和libeio都是经过c和c++来实现的,因此node.js的底层是c和c++。node

tornado的异步主要是经过 ioloop和iostream这2个模块来实现的。ioloop是tornado本身实现的事件驱动模型,和libev同样,也是对poll/epoll的封装,他使用_handlers保存(fd,handler)的映射关系,_events保存就绪的fd以及对应的events事件,tornado提供了add_handler, update_handler、remove_handler这3个方法对handler进行操做。而后调用start函数就能够开始对全部的fd进行轮询,而且调用对应的handler。而iostream是对ioloop的一层封装,主要实现socket的异步调用,主要由如下的3个方法实现读写操做read_until, read_bytes, write。python

从异步的实现方式上面看,在Linux下2者底层都是对poll/epoll的封装,只是一个底层由c实现,另外一个彻底由python实现。ios

从代码风格上讲我以为tornado比node.js有优点,node.js是函数式编程,异步操做处理获得的结果只能经过回调函数进行处理,假如说咱们须要进行多级的函数调用,而且结果互相依赖,那么这个时候就只能在回调函数里面嵌套回调函数,这样的代码可读性和可维护性都不高,好比:c++

当咱们须要读取一个文件的时候,咱们会执行如下语句:web

fs.readFile('/path', function (err, data) {
  if (err) throw err;
  console.log(data);
});

当咱们须要读取一个文件的内容,而且根据这个文件的内容读写另一个文件的时候,咱们就须要执行如下语句:编程

fs.readFile('/path', function (err, data) {
  if (err) throw err;
  fs.readFile(data, function (err, data2) {
    if (err) throw err;
    // 在这里处理data2的数据
  });
});

这个地方咱们就在回调里面嵌套了一层回调,这里仅仅是2层,假如回调嵌套层数不少的话代码就不容易读懂,看起来结构就很乱。后端

tornado为了解决这个问题提供了一种使用同步的方式编码,而且使用异步的方式执行的方法。解决方式就是使用python的yield关键字和gen模块。websocket

gen模块能够把一个函数调用里面的回调函数的参数当成返回值赋给变量,若是有多个参数就返回一个tuple。可是这个并无解决异步调用时间差的问题,若是直接使用这个方法的话获得的值是None,由于回调函数刚刚加入轮询队列,尚未被执行,这个时候gen就尝试读取参数而且返回,这个时候获得的就是None。这个时候就须要yield关键字,这个关键字能够把一个函数变成一个生成器,简单的来讲就是调用一个带有yield关键字的函数的时候,函数会先顺序执行到yield这一句,而后函数被挂起,当这个函数再一次被执行的时候,函数会从yield这一句接着往下执行。若是yield和gen搭配使用的话,函数会先执行到yield这一句,而后把调用的函数加入轮询队列,而后函数被挂起,等待轮询里面的函数执行完毕返回的时候函数再次被调用,经过gen取出回调函数里面的参数而且赋值给变量,函数接着往下执行。例如:网络

若是不使用gen模块的话异步调用须要这样写:

class AsyncHandler(RequestHandler):
    @asynchronous
    def get(self):
        http_client = AsyncHTTPClient()
        http_client.fetch("http://example.com",
                          callback=self.on_fetch)

    def on_fetch(self, response):
        do_something_with_response(response)
        self.render("template.html")

on_fetch就是回调函数

若是使用gen模块代码能够这样写:

class GenAsyncHandler(RequestHandler):
    @gen.coroutine
    def get(self):
        http_client = AsyncHTTPClient()
        response = yield http_client.fetch("http://example.com")
        do_something_with_response(response)
        self.render("template.html")

代码中使用了@gen.coroutine修饰器,而且经过yield关键字将异步的代码变成同步的写法。这样代码的逻辑就很符合大多数人的编程思惟,大大加强了代码的可读性。

总的来讲node.js和tornado都是不错的异步编程工具,对于高并发都有很强的处理能力,node.js更适合全栈式的先后端分离的开发,tornado则是一个轻量级的python框架,他的优点更多的是在对websocket和长链接的支持,知乎就是使用tornado开发的。

相关文章
相关标签/搜索