您的位置:首页 > 其它

flask 源码浅析(flask 如何处理请求(多线程,多进程,IO多路复用))

2018-04-04 13:09 375 查看
之前有阅读过tornado 底层的实现,tornado 为了解决C10K 问题(没听说过C10K问题的请查看: http://www.360doc.com/content/13/0522/18/1542811_287328391.shtml),在Linux 平台下是使用了epoll(python2.6 开始支持epoll),unix 平台下 tornado 使用了kque , 由于flask 之前没有看过底层的实现,因此趁着清明假期看了一下flask,到底是来一个请求使用一个线程呢,还是进程呢,还是IO多路复用。

涉及到的源码文件

site-packages/flask/app.py, site-packages/werkzeug/serving.py, Lib/socketserver.py


首先肯定要先看入口函数啦

app.py
里面的 run 函数

def run(self, host=None, port=None, debug=None, **options):


该函数通过
run_simple(host, port, self, **options)
启动了socket 服务器(
无论是哪个web框架,其实底层都是使用socketserver 监听在某个套接字上来处理请求的
)

run_simple
然后到调用
serving.py
里面的
make_server


make_server
源码定义如下:

def make_server(host=None, port=None, app=None, threaded=False, processes=1,
request_handler=None, passthrough_errors=False,
ssl_context=None, fd=None):
"""Create a new server instance that is either threaded, or forks
or just processes one request after another.
"""
if threaded and processes > 1:
raise ValueError("cannot have a multithreaded and "
"multi process server.")
elif threaded:
return ThreadedWSGIServer(host, port, app, request_handler,
passthrough_errors, ssl_context, fd=fd)
elif processes > 1:
return ForkingWSGIServer(host, port, app, processes, request_handler,
passthrough_errors, ssl_context, fd=fd)
else:
return BaseWSGIServer(host, port, app, request_handler,
passthrough_errors, ssl_context, fd=fd)


可以看到flask 为我们提供了三种方式来处理请求

1 使用多线程来进行处理

2 使用多进程来进行处理

3 使用poll 或者 select IO多路复用的方式进行处理

BaseWSGIServer
这个类是使用IO 多路复用的

下面有个方法
start_forever


def serve_forever(self):
self.shutdown_signal = False
try:
HTTPServer.serve_forever(self)
except KeyboardInterrupt:
pass
finally:
self.server_close()


我们主要来看
HttpServer.serve_forever方法


def serve_forever(self, poll_interval=0.5):
"""Handle one request at a time until shutdown.

Polls for shutdown every poll_interval seconds. Ignores
self.timeout. If you need to do periodic tasks, do them in
another thread.
"""
self.__is_shut_down.clear()
try:
# XXX: Consider using another file descriptor or connecting to the
# socket to wake this up instead of polling. Polling reduces our
# responsiveness to a shutdown request and wastes cpu at all other
# times.
with _ServerSelector() as selector:
selector.register(self, selectors.EVENT_READ)

while not self.__shutdown_request:
ready = selector.select(poll_interval)
if ready:
self._handle_request_noblock()

self.service_actions()
finally:
self.__shutdown_request = False
self.__is_shut_down.set()


_ServerSelector()
定义了 到底该使用select 还是 poll

# poll/select have the advantage of not requiring any extra file descriptor,
# contrarily to epoll/kqueue (also, they require a single syscall).
if hasattr(selectors, 'PollSelector'):
_ServerSelector = selectors.PollSelector
else:
_ServerSelector = selectors.SelectSelector


对于IO多路复用不熟悉的,推荐查看该文章: https://blog.csdn.net/qq546770908/article/details/53082870
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息