Python 3 爬虫-min.png

I/O 密集型最适合使用多线程,当然包括网络 I/O。我们要下载多张图片,每次去下载一张图片,就是发起一次 HTTP 请求(使用 TCP 协议),客户端首先通过 socket.socket() 创建一个套接字,然后调用 connect() 方法经过三次握手与服务端建立 TCP 连接,这个过程是阻塞的。建立连接后,客户端将请求(要访问图片资源)发送给服务端,然后服务端返回响应,客户端用 recv() 方法每次接收一定数量的字节,客户端在每个响应报文(一张图片有多个数据包)到达操作系统内核时,是阻塞的。网络 I/O 对于 CPU 来说是无比漫长的,如果是依序下载,CPU 就要一直阻塞到第 1 张图片的字节全部下载完成后,才能下载第 2 张,这些等待的时间(对 CPU 来说,比它处理数据的时间多出无数倍)就白白浪费了。为了合理利用 CPU 资源,可以使用多线程,每个线程去下载一张图片,当下载第 1 张图片的任务阻塞时,CPU 切换到第 2 个线程,它开始下载第 2 张图片,依次类推,当第 1 张图片有响应报文到达时,等其它线程阻塞后,CPU 又会切换到下载第 1 张图片的那个线程

Python 3 爬虫-min.png

从这一篇开始,将介绍如何用 Python 3 实现网络爬虫,多任务快速抓取你想要的数据。每一次 HTTP 请求/响应都要经过 TCP 连接、客户端发送请求数据、服务端分多次返回响应数据,这个过程中,客户端的 CPU 在等待网络 I/O 时会阻塞。Python 依序下载是一个主线程依次等待每个网络 I/O 完成,而多线程是多个线程并发(不是并行)等待多个网络 I/O,当一个线程因为等待网络 I/O 而阻塞时,会自动切换到另一个线程继续执行,而不是 CPU 浪费时间阻塞在唯一的线程上。所以 I/O 密集型适合用多线程,像加解密、源代码编译等 CPU 密集型适合用多进程(并行)