龙卷风是一个网络异步的的网络开发框架,并且可以利用多进程进行提高效率、下面是创建一个多进程龙卷风程序的例子。
#?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)错误。这时候回调函数判断是这个错误则返回函数不做处理。
当成功建立连接的子进程还在处理这个连接的时候又过来一个连接,这时候就会有另外一个子进程接手这个连接。
龙卷风就是通过这样一种机制,利用多进程提升效率,由于连接只能由一个子进程成功创建,同一个请求也就不会被多个子进程处理。