📋 个人简介
💖 作者简介:大家好,我是W_chuanqi,一个编程爱好者
💬 愿你我共勉:“若身在泥潭,心也在泥潭,则满眼望去均是泥潭;若身在泥潭,而心系鲲鹏,则能见九万里天地。”✨✨✨

requests中多线程爬取怎么避免漏数据 多线程爬虫原理_多线程


文章目录

  • 第1章 爬虫基础
  • 1.6 多线程和多进程的基本原理
  • 1.多线程的含义
  • 2.并发和并行
  • 3.多线程适用场景
  • 4.多进程的含义
  • 5. Python 中的多线程和多进程


第1章 爬虫基础

1.6 多线程和多进程的基本原理

在一台计算机中,我们可以同时打开多个软件,例如同时浏览网页、听音乐、打字等,这是再正常不过的事情。但仔细想想,为什么计算机可以同时运行这么多软件呢?这就涉及计算机中的两个名词:多进程和多线程。

同样,在编写爬虫程序的时候,为了提高爬取效率,我们可能会同时运行多个爬虫任务,其中同样涉及多进程和多线程。

1.多线程的含义

说起多线程,就不得不先说什么是线程。说起线程,又不得不先说什么是进程。

进程可以理解为一个可以独立运行的程序单位,例如打开一个浏览器,就开启了一个浏览器进程;打开一个文本编辑器,就开启了一个文本编辑器进程。在一个进程中,可以同时处理很多事情,例如在浏览器进程中,可以在多个选项卡中打开多个页面,有的页面播放音乐,有的页面播放视频,有的网页播放动画,这些任务可以同时运行,互不干扰。为什么能做到同时运行这么多任务呢?这便引出了线程的概念,其实一个任务就对应一个线程。

进程就是线程的集合,进程是由一个或多个线程构成的,线程是操作系统进行运算调度的最小单位,是进程中的最小运行单元。以上面说的浏览器进程为例,其中的播放音乐就是一个线程,播放视频也是一个线程。当然,浏览器进程中还有很多其他线程在同时运行,这些线程并发或并行执行使得整个浏览器可以同时运行多个任务。

了解了线程的概念,多线程就很容易理解了。多线程就是一个进程中同时执行多个线程,上面的浏览器进程就是典型的多线程。

2.并发和并行

说到多进程和多线程,不得不再介绍两个名词——并发和并行。我们知道,在计算机中运行一个程序,底层是通过处理器运行一条条指令来实现的。

处理器同一时刻只能执行一条指令,并发(concurrency)是指多个线程对应的多条指令被快速轮换地执行。例如一个处理器,它先执行线程 A 的指令一段时间,再执行线程 B 的指令一段时间,然后再切回线程 A执行一段时间。处理器执行指令的速度和切换线程的速度都非常快,人完全感知不到计算机在这个过程中还切换了多个线程的上下文,这使得多个线程从宏观上看起来是同时在运行。从微观上看,处理器连续不断地在多个线程之间切换和执行,每个线程的执行都一定会占用这个处理器的一个时间片段,因此同一时刻其实只有一个线程被执行。

并行(parallel)指同一时刻有多条指令在多个处理器上同时执行,这意味着并行必须依赖多个处理器。不论是从宏观还是微观上看,多个线程都是在同一时刻一起执行的。

并行只能存在于多处理器系统中,因此如果计算机处理器只有一个核,就不可能实现并行。而并发在单处理器和多处理器系统中都可以存在,因为仅靠一个核,就可以实现并发。

例如,系统处理器需要同时运行多个线程。如果系统处理器只有一个核,那它只能通过并发的方式来运行这些线程。而如果系统处理器有多个核,那么在一个核执行一个线程的同时,另一个核可以执行另一个线程,这样这两个线程就实现了并行执行。当然,其他线程也可能和另外的线程在同一个核上执行,它们之间就是并发执行。具体的执行方式,取决于操作系统如何调度。

3.多线程适用场景

在一个程序的进程中,有一些操作是比较耗时或者需要等待的,例如等待数据库查询结果的返回、等待网页的响应。这时如果使用单线程,处理器必须等这些操作完成之后才能继续执行其他操作,但在这个等待的过程中,处理器明显可以去执行其他操作。如果使用多线程,处理器就可以在某个线程处于等待态的时候,去执行其他线程,从而提高整体的执行效率。

很多情况和上述场景一样,线程在执行过程中需要等待。网络爬虫就是一个非常典型的例子,爬虫在向服务器发起请求之后,有一段时间必须等待服务器返回响应,这种任务就属于 IO 密集型任务。对于这种任务,如果我们启用多线程,那么处理器就可以在某个线程等待的时候去处理其他线程,从而提高整体的爬取效率。

但并不是所有任务都属于 IO 密集型任务,还有一种任务叫作计算密集型任务,也可以称为CPU密集型任务。顾名思义,就是任务的运行一直需要处理器的参与。假设我们开启了多线程,处理器从一个计算密集型任务切换到另一个计算密集型任务,那么处理器将不会停下来,而是始终忙于计算,这样并不会节省整体的时间,因为需要处理的任务的计算总量是不变的。此时要是线程数目过多,反而还会在线程切换的过程中耗费更多时间,使得整体效率变低。

综上所述,如果任务不全是计算密集型任务,就可以使用多线程来提高程序整体的执行效率。尤其对于网络爬虫这种 IO 密集型任务,使用多线程能够大大提高程序整体的爬取效率。

4.多进程的含义

前文我们已经了解了进程的基本概念,进程(process)是具有一定独立功能的程序在某个数据集合上的一次运行活动,是系统进行资源分配和调度的一个独立单位。

顾名思义,多进程就是同时运行多个进程。由于进程就是线程的集合,而且进程是由一个或多个线程构成的,所以多进程意味着有大于等于进程数量的线程在同时运行。

5. Python 中的多线程和多进程

Python中 GIL 的限制导致不论是在单核还是多核条件下,同一时刻都只能运行一个线程,这使得Python 多线程无法发挥多核并行的优势。

GIL 全称为 Global Interpreter Lock,意思是全局解释器锁,其设计之初是出于对数据安全的考虑。
在 Python 多线程下,每个线程的执行方式分如下三步。

  • 获取 GIL。
  • 执行对应线程的代码。
  • 释放GIL。

可见,某个线程要想执行,必须先拿到 GIL。我们可以把 GIL 看作通行证,并且在一个Python 进程中,GIL 只有一个。线程要是拿不到通行证,就不允许执行。这样会导致即使在多核条件下,一个Python 进程中的多个线程在同一时刻也只能执行一个。

而对于多进程来说,每个进程都有属于自己的 GIL,所以在多核处理器下,多进程的运行是不会
受GIL 影响的。也就是说,多进程能够更好地发挥多核优势。

不过,对于爬虫这种 IO 密集型任务来说,多线程和多进程产生的影响差别并不大。但对于计算密集型任务来说,由于 GIL 的存在,Python 多线程的整体运行效率在多核情况下可能反而比单核更低。而 Python 的多进程相比多线程,运行效率在多核情况下比单核会有成倍提升。

从整体来看,Python 的多进程比多线程更有优势。所以,如果条件允许的话,尽量用多进程。

行效率在多核情况下比单核会有成倍提升。

从整体来看,Python 的多进程比多线程更有优势。所以,如果条件允许的话,尽量用多进程。

值得注意的是,由于进程是系统进行资源分配和调度的一个独立单位,所以各进程之间的数据是无法共享的,如多个进程无法共享一个全局变量,进程之间的数据共享需要由单独的机制来实现。