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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM