龙卷风多进程实现分析详解

  

  

龙卷风是一个网络异步的的网络开发框架,并且可以利用多进程进行提高效率、下面是创建一个多进程龙卷风程序的例子。

        #?usr/bin/env python   # - * -编码:utf - 8 - *   进口操作系统   导入的时间      进口tornado.web   进口tornado.httpserver   进口tornado.ioloop   进口tornado.netutil   进口tornado.process         类LongHandler (tornado.web.RequestHandler):      def(自我):   self.write (str (os.getpid ()))   time . sleep (10)         if __name__==癬_main__”:   应用=tornado.web。应用程序(((r '/', LongHandler)))   套接字=tornado.netutil.bind_sockets (8090)   tornado.process.fork_processes (2)   服务器=tornado.httpserver.HTTPServer(应用)   server.add_sockets(插座)   .start tornado.ioloop.IOLoop.instance () ()      

上面代码使用tornado.process。fork_processes创建了两个子进程,同时用时访问这个服务两次,分别会返回两个相邻的pid。可以看到龙卷风确实使用了两个进程来同时完成任务。

  

我一直很好奇龙卷风是如何将请求调度到子进程,多个子进程又如何不同时处理一个请求呢& # 63;

  

  

我们首先是调用tornado.netutil.bind_sockets来创建一个套接字(或一个套接字列表),

  

接着我们调用tornado.process。fork_processes来叉子进程,阅读此函数的代码会发现这个函数仅仅是创建子进程,然后主进程负责等待子进程,如果子进程退出则会根据条件重启子进程,如果子进程全部退出并不符合重启条件,则主进程退出。

  

调用这个函数之后,子进程中函数会返回,子进程则继续执行调用这个函数之后的代码。

  

我们在叉子进程后做了如下操作。

        服务器=tornado.httpserver.HTTPServer(应用)   server.add_sockets(插座)   .start tornado.ioloop.IOLoop.instance () ()      

我们先看看tornado.httpserver.HTTPServer。add_sockets发现HTTPServer是继承的tornado.netutil.TCPServer, add_sockets也是实现在TCPServer中

  

tornado.netutil.TCPServer.add_sockets         def add_sockets(自我,套接字):   如果自我。io_loop没有:   自我。io_loop=IOLoop.instance ()      的袜子套接字:   self._sockets [sock.fileno()]=袜子   self._handle_connection add_accept_handler(袜子,   io_loop=self.io_loop)      

主要是映射了下套接字和套接字对应的文件描述符,我们看看它调用的add_accept_handler

        def add_accept_handler(袜子,回调,io_loop=None):   如果io_loop没有:   io_loop=IOLoop.instance ()      def accept_handler (fd、事件):   而真正的:   试一试:   连接,地址=sock.accept ()   除了插座。误差e:   如果e。args (errno [0]。EWOULDBLOCK errno.EAGAIN):   返回   提高   回调(连接,地址)   io_loop.add_handler (sock.fileno ()、accept_handler IOLoop.READ)      

我们知道I/O多路复用在处理服务端套接字时,当有连接请求过来时,会触发可读的事件,此函数将套接字在主事件循环中注册读事件(IOLoop.READ),它的回调会创建连接,我注意到回调里的异常捕获有这样几行

        如果e。args (errno [0]。EWOULDBLOCK errno.EAGAIN):   返回   提高      

发现在创建连接的时候会跳过这个异常呢,为什么& # 63;那么EWOULDBLOCK和EAGAIN是是什么呢& # 63;通过查找知道它的意思是在非阻塞模式下,不需要重读或重写,EAGAIN是EWOULDBLOCK在Windows上的名字,所以看到这里就很明确了。

  

  

龙卷风多进程的处理流程是先创建窝,然后再叉子进程,这样所有的子进程实际都监听一个(或多个)文件描述符,也就是都在监听同样的插座。

  

当连接过来所有的子进程都会收到可读事件,这时候所有的子进程都会跳到accept_handler回调函数,尝试建立连接。

  

一旦其中一个子进程成功的建立了连接,当其他子进程再尝试建立这个连接的时候就会触发EWOULDBLOCK(或EAGAIN)错误。这时候回调函数判断是这个错误则返回函数不做处理。

  

当成功建立连接的子进程还在处理这个连接的时候又过来一个连接,这时候就会有另外一个子进程接手这个连接。

  

龙卷风就是通过这样一种机制,利用多进程提升效率,由于连接只能由一个子进程成功创建,同一个请求也就不会被多个子进程处理。

龙卷风多进程实现分析详解