环境 windows python3.6 jupyter notebook
没有使用 requests.Session,只是单纯的 get 请求,
我把 线程数量控制在 os.cpu_count()后问题解决,
但是 这样就只能开 8 个线程,效率就低很多了。
1
cz5424 2020-03-04 19:00:23 +08:00
你用多进程试试?
|
2
ysc3839 2020-03-04 19:06:11 +08:00 via Android
怀疑是连接池的什么 bug ?多个线程同时请求的时候重复使用了已经建立连接的 socket。
不过具体如何还得调试看看了,得先找到哪出的错误,再一步步回溯。 |
3
1462326016 2020-03-05 09:38:45 +08:00
直接 get 的话其实内部就是 with session as xx: 所以你其实是每一个请求开了一个连接池,可能频繁的发送请求,会导致系统回收一些端口不及时导致这个问题。
两个方案: 1. 多个线程共享一个 session,注意加锁,因为目前没办法证明它是线程安全的,我也没详细看过源码。 2. 使用异步,按照你现在的情况来看应该不会是很复杂的请求,只是效率问题。异步可以增加效率。例如 aiohttp。 |
4
ClericPy 2020-03-05 09:58:49 +08:00
楼主也不给点代码看看到底哪的问题, 这样提问题让人很困扰啊, 只看报错的话, 不像是客户端(也就是 requests) 的问题, 反而像是你在同一个端口下开了多个 server 报的错, 没有代码也猜不了更多了
另外提 requests 并发的几个常识吧 1. 多线程并不是越多越快, 毕竟压根又用不到多核 CPU, 直接用官方建议的并发数比较合理, https://docs.python.org/zh-cn/3/library/concurrent.futures.html#concurrent.futures.ThreadPoolExecutor , 以前默认为机器处理器的个数, 3.8 以后又建议了 min(32, os.cpu_count() + 4). 2. 如果是 Windows 操作系统, 那就更不用考虑把并发数开大了, 别说开到几千, 开到五六百可能就超了 Windows 的单进程默认最大 文件描述符(句柄) 限制而报错了, 在 GIL 的作用下, 走协程+多路复用的路子比传统多线程要合理的多. 3. 如果真想要性能, requests 比 aiohttp 慢了 4 倍, 而且还是在 Windows 上无法启用 uvloop 提速的前提下, 协程开销比线程小很多, 也快很多, aiohttp 有 Cython 加成, 也比同样是协程的 httpx 快一大截. 4. requests 的 Session 是共享连接池的一套逻辑, 速度比 requests.get 快一大截, 毕竟后者每次要开启一个新的 Session, 也就创建新的连接. PS: 就我目前测试结果来看, 是线程安全的, 没必要加无谓的锁 5. 突破默认 http 适配器连接数上限也可以用以下代码来实现 custom_adapter = HTTPAdapter( pool_connections=n, pool_maxsize=n) session.mount("http://", custom_adapter) session.mount("https://", custom_adapter) |
5
wuwukai007 OP @ClericPy 多谢回答,我改成了 gevent 方式做异步处理,效率提高了蛮多的,也不存在套接字那个问题了,就是有一个缺点,gevent 在 windows 中套接字限制 1024,所有 只能把每次的请求数量限制在 1000 之内,看了下 asyncio 的文档,应该也会有这个限制,windows 问题。
|