第三章 使用并行编程

先前,我们简单了解了爬虫的基本原理,但仅仅只有初级功能的爬虫,并不能满足我们业务对于爬虫效率上的要求。

有时候,当我们需要执行多个爬虫时,我们可能需要启用多线程或者多进程,避免单个任务罢工,影响整个程序的运行。在一些大规模爬虫任务之中,网络请求与等待可能会非常耗时,所以我们就需要增加任务量,来提升效率。所以,了解学习并行/并发相关知识还是有必要的。

1. 关于并行(并发)编程

并行编程可以被定义为一种模型,这个模型旨在创造一种能与被准备用于同时执行代码指令的环境相兼容的程序。

我们知道,在Core(R)系列产品中,处理器的内核也被称为逻辑处理器,让我们可以同时并行的执行一个程序的不同的部分,甚至同时执行不同的程序。

因此,在系统开发的所有情况下,从手机、电脑到研究中心的重型计算,并行编程都是现实的。通过运用并行编程,开发人员可以方便地优化一个应用的性能。这会增强用户体验以及计算资源的消费,从而减少完成复杂任务的处理时间。

让我们想象一个并行性的场景,在这个场景中,有一些任务,其中一个任务是从大规模数据库中检索一些信息。再假如,这个应用还需要顺序执行,在这个应用中,这些任务必须以一定的逻辑顺序,一个接一个的执行。当用户请求数据时,在返回的数据没有结束之前,其它系统将一直被阻塞。然而,利用并行编程,我们将会创造一个新的worker来在数据库中查询信息,而不会阻塞这个应用的其它功能,从而提高它的使用。

2. 常见的并行化形式

当我们试图定义并行系统的主要模式时,有困惑很正常。常常会有人提到并发系统和并行系统,下面我们就对二者进行一下区分。

  • 并发(concurrency),是指能处理多个同时性活动的能力,并发事件之间不一定要同一时刻发生。
  • 并行(parallelism)是指同时发生的两个并发事件,具有并发的含义,而并发则不一定并行。
  • 并发和并行的区别就是一个处理器同时处理多个任务和多个处理器或者是多核的处理器同时处理多个不同的任务。
  • 前者是逻辑上的同时发生(simultaneous),而后者是物理上的同时发生

打个比方:并发和并行的区别就是1个人同时吃3个馒头和3个人同时吃3个馒头。

还有一个并行系统就是分布式了,分布式编程旨在在物理分离的计算机器(节点)之间通过消息交换数据来分享进程。

分布式编程变得越来越受欢迎的原因有很多,比如:

  • 容错性:由于系统是去中心化的,我们可以分发执行到同一个网络的不同机器,从而执行指定机器的个人维护而不影响整个系统的功能。
  • 横向扩展:通常我们可以在分布式系统中增加处理的性能。我们可以在不需要终止正在执行的应用的情况下连接新的设备。
  • 云计算:随着硬件成本的降低,我们需要这种业务类型的增长,在这种增长中,我们可以获得巨大的机器集群,这些集群对用户来说以一种合作的方式运行并且以一种透明的方式运行程序。

下图显示了一个分布式系统的方案:

(3)并行编程中通信

在并行编程中,workers被送来执行任务,而执行任务常常需要建立通信,以便可以合作解决一个问题。这里主要有两种通信方式:共享状态和消息传递。

理解共享状态

分享状态似乎是一个简单的使用,但是这会有许多的陷阱,因为若其中某个进程对共享的资源执行了一项无效的操作会影响到所有其它的进程,从而导致一个不好的结果。这也是使在多台计算机之间进行分布式的程序成为不可能的显而易见的原因。

比如有一家银行,而这个银行只用一个收银员。当你去银行,你必须要排队等到轮到你的时候。当你在队列中时,你注意到收银员一次只能为一个顾客服务,而收银员不可能同时为两个顾客提供服务而不出错。

在某些情况下,当程序正在运行时,在一个变量中数据会有一个常数值,数据仅仅以只读的目的被分享。所以访问控制不是必须的,因为永远不会出现完整性问题。

理解信息传递

运用消息传递是为了避免来自共享状态带来的数据访问控制以及同步的问题。消息传递包含一种在运行的进程中进行消息交换的机制。每当我们用分布式架构开发程序的时候,就能见到消息传递的使用。

在网络中,消息交换被放在一个重要的位置。由于每次数据交换都复制一份数据的拷贝,因此不会出现并发访问的问题。尽管内存使用看起来比共享内存状态要高,但是这个模型还是有一些优势的。优势如下:

  • 缺乏数据的一致性访问
  • 数据即可在本地交换(不同的进程)也能在分布式环境中交换
  • 不太可能出现扩展性问题,并且允许不同系统相互写作。
  • 一般来说,相对易于维护。

(4)几个 Python 并行编程模块

threading模块

Python的threading模块提供了一个抽象层次的模块_thread,这是一个低层次的模块。当开发一个基于线程的并行系统的艰巨任务时,它为程序员提供了一些函数来帮助程序员的开发。如有疑问,请查阅官方文档

mutliprocess模块

multiprocessing模块旨在为基于进程的并行的使用提供一个简单的API。这个模块与线程模块类似,它简化了基于进程的并行系统的开发,这一点与线程模块没有什么不同。在Python社区中,基于进程的方法很流行,因为它是在解决出现在Python中CPU-Bound threads和GIL的使用的问题时的一个解决方案。我们可以在官方文档之中找到。

Celery-分布式任务队列

Celery是一个用于创建分布式系统的极其优秀的模块,并且拥有很好的文档。它在并发形式上使用了至少三种不同类型的方法来执行任务:multiprocessing, Eventlet,和 Gevent。这项工作将会集中精力在多进程的方法的使用上。而且,只需要通过配置就能实现进程间的互联,这被留下来作为一个研究,以便读者能够建立一个与他/她的实验的一个比较。

Celery模块可以在官方的项目页面http://celeryproject.org得到。

results matching ""

    No results matching ""