from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
return 'Hello Flask'
if __name__ == '__main__':
app.run()
假设现在有这么一个最简单的 Flask 代码,Flask 会根据 Request 产生相对应的 Response。
那么,Flask 自带的 WSGI 服务器是以何种方式处理请求的呢?比如说是 单进程多线程,多进程多线程还是单进程单线程?
1
windardyang 2018-07-24 17:32:18 +08:00 1
|
2
KeatingSmith OP @windardyang
如果是这样的话,我进行测试过。代码如下: ```python @app.route('/') def index(): time.sleep(10) return 'Hello Flask' ``` 假如是默认是单进程单线程,我开启了 10 个网页,是不是第 10 个网页应该在 100s 后才能接收到 Response,但是实际测试的时候,并不是? ```shell $ gunicorn -w 4 xxx:app ``` 使用 Gunicorn 运行的话,相当于开启了四个进程,那也就是说,四个进程也是单线程模式? 我找了很多资料,也没有找到答案,请前辈赐教。 |
3
windardyang 2018-07-24 17:51:43 +08:00 1
|
4
ox180 2018-07-24 17:59:04 +08:00 1
问题一:
由于 Flask 代码中默认启用了多线程,如下: ```python # 大致在 936 行 options.setdefault('use_reloader', self.debug) options.setdefault('use_debugger', self.debug) options.setdefault('threaded', True) # here cli.show_server_banner(self.env, self.debug, self.name, False) from werkzeug.serving import run_simple try: run_simple(host, port, self, **options) # 此处启动 server finally: # reset the first request information if the development server # reset normally. This makes it possible to restart the server # without reloader and that stuff from an interactive shell. self._got_first_request = False ``` 然后再往下走,此处忽略,然后最终到达: ```python 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 问题二: -w 表示启动多少个 worker,简单来讲就是启动几个 flask app 副本,一种简单实现方式: ```python # 伪代码 def start(app, worker=4, *args, **kwargs): workers = [Process(target=app, args=()) for _ in range(worker)) for _worker in workers: _worker.start() # 如果你看 sanic,其实也是这个实现方式 ``` 所以关于 gunicorn,我的理解就是启动-w 个 flask 程序,如你描述那就是 4 个 flask 进程,至于是不是单进程多线程方式,那是另外一个问题了.... |
5
KeatingSmith OP |
6
ClericPy 2018-07-24 19:08:53 +08:00
不要用浏览器测并发
浏览器尤其 chrome 会限制对同一个域名的连接... 刚开始学 python 的时候调了很久很久不知道为什么 gevent 开的 flask 就是没法同时打开多个网页... 结果用脚本测并发完全正常 |
7
ClericPy 2018-07-24 19:10:17 +08:00 1
就因为上面的问题, 用 chrome 多 tab 没法对同一个网站提高并发, 最后我是启动了多个 chrome user 才解开的, 求更好更优雅的操作 chrome 方式... cdp 爬虫还有很多小细节等待发现
|
8
KeatingSmith OP |
10
vipppppp 2018-07-25 09:51:37 +08:00
|
11
Nostalgiaaaa 2018-07-25 09:55:34 +08:00
先马个,最近在读 flask 源码,读好了写文档 @楼主
|
12
KeatingSmith OP |
13
KeatingSmith OP |
14
gnozix 2018-07-25 16:42:35 +08:00
|
17
windardyang 2018-07-26 14:08:43 +08:00
@vipppppp 1 楼是太匆忙写反了,Thread 表示线程,Process 表示进程。
|
18
luffysup 2018-07-27 17:48:32 +08:00
@windardyang 细致
|
19
Nostalgiaaaa 2018-07-29 22:34:47 +08:00
@KeatingSmith 感觉摊的有点大,写了一部分你先看看吧 别忘了点个 star,这个还会持续更新。https://python-fbw.gitbook.io/flask/
这次看完 Flask 会看 werkzeug 的一部分代码,之后会再看 Request 的代码,每周都能更新三四次。 |