【声明】本博客所有内容均为个人业余时间创作,所述技术案例均来自公开开源项目(如Github,Apache基金会),不涉及任何企业机密或未公开技术,如有侵权请联系删除
背景
上篇 blog
【Ubuntu】【Gitlab】拉出内网 Web 服务:http.server 单/多线程分析(一)
分析了 Python http.server 模块默认启用的是多线程模型,并对单线程启动做了测试,下面继续
Python http.server 单/多线程分析
首先是之前 blog 提到,启动了 slow_server.py 之后,在终端输入
bash
time curl http://localhost:2027/a
去查询该 Web 服务的响应时间如下

可以看到需要 10s 的时间 Web 服务才能响应,这和 SlowHandler 里面定义的 10s 休眠时间是一样的

这里的一个小技巧是,访问 \a 这样一个不存在的页面,只返回一个 404 错误码,不然 curl 返回的内容可就太多了
然后再接着做一个测试,在输入 time curl http://localhost:2027/a 的同时,在另一个终端再输入 time curl http://localhost:2027/b,模拟并发访问的情况
可以看到,访问 \a 页面的等待时间依旧是 10s(因为是先点开访问的)

而后点开访问 \b 页面的等待时间则来到了 18s(不是 10s)

这就足以说明,\a 页面访问的处理,阻塞了 \b 页面访问的处理,这就是上篇 blog 里提到的 HTTPServer 继承了 TCPServer 默认的单线程同步处理能力
再来看下,如果是多线程启动,修改 slow_handler.py 如下
python
#!/usr/bin/env python3
from http.server import ThreadingHTTPServer, SimpleHTTPRequestHandler
import time
class SlowHandler(SimpleHTTPRequestHandler):
def do_GET(self):
print(f"Handling {self.path} ... (will sleep 10s)")
time.sleep(10) # 模拟耗时操作
"""Serve a GET request."""
f = self.send_head()
if f:
try:
self.copyfile(f, self.wfile)
finally:
f.close()
server = ThreadingHTTPServer(('localhost', 2028), SlowHandler)
server.serve_forever()
其实就是把 HTTPServer 给换成 ThreadingHTTPServer,然后端口换一下

其他地方不变,再次运行 slow_handler.py,然后在两个终端分别输入 time curl http://localhost:2028/a 和 time curl http://localhost:2028/b 同时访问两个页面
可以看到,访问 \a 页面的时间是 10s(先访问)

而访问 \b 页面的时间也同样是 10s(后访问)

可以看到,在多线程下,出现并发操作同时访问,两者的时间基本一致,因为访问 \b 页面时会新开一个线程进行处理,而不用等待 \a 页面访问结束
OK,再说一个有意思的点,上篇 blog 里提到,当前的 Python 版本为 v3.12.3,此时默认的是启动多线程 Web 访问,http.server 作为 Python 里的标准库模块,其源码在 CPython 仓库中
GitHub 地址:https://github.com/python/cpython/blob/main/Lib/http/server.py
国内访问 GitHub 比较慢,可以参考下 Gitee 的同步镜像仓库(Gitee 官方维护,自动同步 GitHub 仓库的镜像,更新及时,可信度高 )
Gitee 地址:https://gitee.com/mirrors/cpython/

点击标签

找到 v3.6.15 版本(21年9月),这是 v3.6 的最后一个版本

可以看到这个时候,http.server 模块默认启动的,还是单线程 Web 服务

而到了 v3.7.0 版本时(v3.7 的第一个版本)

http.server 模块被改成了默认多线程启动

所以 python -m http.server 在 Python < v3.7 时无法并发处理请求,只有等一个请求处理完,才能轮到下一个,所以只要有一个请求慢(比如大文件下载、time.sleep),整个服务器对外表现就是卡住了,用户体验不好,所以这里 Python 3.7 是一个分水岭,官方为了提升开发体验,把命令行服务器升级为多线程
OK,本篇先到这里,如有疑问,欢迎评论区留言讨论,祝各位功力大涨,技术更上一层楼!!!更多内容见下篇 blog
【Ubuntu】【Gitlab】拉出内网 Web 服务:http.server 单/多线程分析(三)