ClericPy
2020-08-08 19:03:25 +08:00
看到有几个回复挺反常识的, 提醒几个 Python 并发编程的常识问题吧
1. 线程开的越多, 执行起来就越快吗?
并不会.
一方面, 线程开太多, CPU 切换的成本会变高, 也就相对降低了 CPU 利用率, CPU 很多时间浪费在调度上而不是计算上. 有关怎么切换的, 可以随处找找 GIL 的文章, 不过还是不建议自己修改对应参数 setswitchinterval (旧版本的 setcheckinterval )
另一方面, 对爬虫来说, 如果连接速度靠谱的话, 有可能一个线程就跑满了带宽, 那开多线程除了让所有任务一起抢资源, 并不会降低总时长, 也就是常见场景: 为什么我开 5 线程比开 100 线程还快(或者差不多). 与普通程序不同, 爬虫程序传输数据一方面看你的带宽, 另一方面还特别看重目标服务器的负载能力.
2. 有一个比较合理的并发数量吗?
参考:
Python3 里面 ThreadPoolExecutor 的 max_workers 默认值是 (os.cpu_count() or 1) * 5
可以根据带宽使用率适当调整这个数值.
(另: 多进程 ProcessPoolExecutor 默认 max_workers 就是 os.cpu_count() or 1)
3. 不计带宽和 CPU 能力的情况下, 是不是线程开的越多, 速度越快?
也不完全是.
拿 Requests 库来举例, 它的 Session 默认连接池大小取决于 HTTPAdapter 对象的 pool_connections, 这个默认值 DEFAULT_POOLSIZE = 10
简单的说, 如果不修改 HTTPAdapter 连接池的大小, 那可能瓶颈基本限定在这里了. 至于有些人选择不用 Session 复用连接, 我举个例子算了: 之前抓某东的某数据, 复用连接的情况下速度比每次新建连接大概快了十几倍.
4. 是不是用协程就比线程快, 节省 CPU?
不一定.
协程提高的是 CPU 效率, 遇到高并发的抓取, 你会发现协程 CPU 一直 100%, 因为它真的很忙, 而多线程反而可能在 80~100% 波动. 至于速度, 简单的提个例子, falcon 那是相当擅长 Benchmark.
协程中最使我受益的并不是性能, 而是它属于随时可以 Cancel 的, 一个已经执行的线程, 想在外部杀死它简直太费劲了.