zoukankan      html  css  js  c++  java
  • flask 源码浅析(flask 如何处理请求(多线程,多进程,IO多路复用))

     

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
    本文链接:https://blog.csdn.net/lucky404/article/details/79815997

    之前有阅读过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)
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    可以看到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()
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    我们主要来看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()
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    _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
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    对于IO多路复用不熟悉的,推荐查看该文章: https://blog.csdn.net/qq546770908/article/details/53082870

  • 相关阅读:
    【常用】source insight常用设置及快捷键
    【Linux学习】配置环境:实现【VirtualBox + ubuntu】+【开启ssh服务】+【putty远程连接到虚拟机】
    javascript:区别浏览器
    linux 之centos6.3 安装中文输入法
    前端优化(静态资源)
    javascript 学习心得!
    编程总结
    2019年春季学期第二周作业
    HTTP could not register URL http://+:8000/testservice/. Your process does not have access rights to this namespace 解决方案
    [原]ASP.NET MVC 3 Razor + jqGrid 示例
  • 原文地址:https://www.cnblogs.com/fengff/p/11636990.html
Copyright © 2011-2022 走看看