• 《Python高级编程》

  • 价格:免费
  • 状态:全书已完结
  • 在读人数:24
  • 热度:1548
创建者
  • APAC
  • 18 粉丝 33博客
内容简介
本书是一本有内涵的关于Python并行编程的教程。对于那些希望写出高效率的Python程序员来说,这本书绝对是值得花点时间一看的好东西。
章节目录
  • 第一章 并行计算和Python基础
  • 1.1 简介
  • 本章将介绍一些并行编程的架构和编程模型。对于初次接触并行编程技术的程序员来说,这些都是非常有用的概念;对于经验丰富的程序员来说,本章可以作为基础参考。 本章中讲述了并行编程的两种解释,第一种解释是基于系统架构的,第二种解释基于程序示例F。 并行编程对程序员
  • 1.2 初识费林分类
  • 根据指令的同时执行和数据的同时执行,计算机系统可以分成以下四类: 1.单处理器,单数据 (SISD) 2,单处理器,多数据 (SIMD) 3.多处理器,单数据 (MISD) 4.多处理器,多数据 (MIMD) 这种分类方法叫做"费林分类":SISD 单处理器单数据就是"单CPU的
  • 1.3 内存管理
  • 内存管理是并行架构需要考虑的另一方面,确切来说是获得数据的方式。无论处理单元多快,如果内存提供指令和数据的速度跟不上,系统性能也不会得到提升。制约内存达到处理器速度级别的响应时间的主要因素是内存存取周期。所谓存取周期就是连续启动两次读或
  • 1.4 并行编程模型
  • 并行编程模型是作为对硬件和内存架构的抽象而存在的。事实上,这些模式不是特定的,而且和机器的类型或内存的架构无关。他们在理论上能在任何类型的机器上实现。相对于前面的架构细分,这些编程模型会在更高的层面上建立,用于表示软件执行并行计算时必须实现的方式。为了访问内存和分解任务,每一个模型都以它独自的方式和其他处理器共享信息。需要明
  • 1.5 如何设计一个并行程序
  • 并行算法的设计是基于一系列操作的,在编程的过程中必须执行这些操作来准确地完成工作而不会产生部分结果或错误结果。并行算法地大致操作如下: 1.任务分解 (Task decomposition) 2.任务分配 (Task assignment) 3.聚合 (Agglomeration)4.映射 (Mapping)任务分解 第一阶段,将软件程序分解为可以在不同处理器执
  • 1.6 如何评估并行程序的性能
  • 并行编程的发展产生了对性能指标和并行程序评估软件的需求,通过评估性能才能确定该算法是否方便快捷。实际上,并行计算的重点是在相对较短的时间内解决体量较大的问题。为了能够达到这个目的,需要考虑的因素有:使用的硬件类型,
  • 1.7 Python简介
  • Python是一种动态的解释型语言,应用场景广泛。它具有以下特性: 1.简明、易读的语法 2.丰富的标准库。通过第三方的软件模块,我们可以方便地添加数据类型、函数和对象 3.上手简单,开发和调试速度快。Python代码的开发速度可能比C/C++快10倍 4.基于Exception的错误处理机制 5.强大的自省功能 6.丰富的文档和活跃的社区 Python也可
  • 1.8 并行世界的Python
  • 作为一种解释型的语言,Python的速度并不算慢。如果对速度有很高的要求的话,可以选择用更快的语言实现,比如C或C++,然后用Python调用。Python的一种常见应用场景是实现高级的逻辑。Python的解释器就是用C语言写的,即CPython。解释器将Pyth
  • 1.9 线程和进程
  • 进程是应用程序的一个执行实例,比如,在桌面上双击浏览器图标将会运行一个浏览器。线程是一个控制流程,可以在进程内与其他活跃的线程同时执行。"控制流程"指的是顺序执行一些机器指令。进程可以包含多个线程,所以开启一个浏览器,操作系统将创建一个进程,并
  • 1.10 开始在Python中使用进程
  • 在大多数操作系统中,每个程序在一个进程中运行。通常,我们通过双击一个应用程序的图标来启动程序。在本节中,我们简单地展示如何在Python中开启一个进程。进程有自己的地址空间,数据栈和其他的辅助数据来追踪执行过程;系统会管理所有进程的执行,通过调度程序
  • 1.11开始在Python中使用线程
  • 如前面章节提到的那样,基于线程的并行是编写并行程序的标准方法。然而,Python解释器并不完全是线程安全的。为了支持多线程的Python程序,CPython使用了一个叫做全局解释器锁(Global Interpreter Lock, GIL)的技术
  • 第二章 基于线程的并行
  • 2.1 背景
  • 目前,在软件应用中使用最广泛的并发编程范例是多线程。通常,一个应用有一个进程,分成多个独立的线程,并行运行、互相配合,执行不同类型的任务。虽然这种模式存在一些缺点,有很多潜在的问题,但是多线程的应用依然非常广泛。现在几乎所有的操作系统都支持多线程,几乎所有的编程语言都有相应
  • 2.2 使用Python的线程模块
  • Python通过标准库的 threading 模块来管理线程。这个模块提供了很多不错的特性,让线程变得无比简单。实际上,线程模块提供了几种同时运行的机制,实现起来非常简单。线程模块的主要组件如下: 1.线程对象 2.Lock对象 3.RLock对象 4.信号对象 5.条件对象 6.事件对象 在接下来的子章节中,我们将通过例
  • 2.3 如何定义一个线程
  • 使用线程最简单的一个方法是,用一个目标函数实例化一个Thread然后调用 start() 方法启动它。Python的threading模块提供了 Thread() 方法在不同的线程中运行函数或处理过程等。 : class threading.Thread(group=None,target=None,name=None,args=(),kwargs={}) 上面
  • 2.4 如何确定当前的线程
  • 使用参数来确认或命名线程是笨拙且没有必要的。每一个 Thread 实例创建的时候都有一个带默认值的名字,并且可以修改。在服务端通常一个服务进程都有多个线程服务,负责不同的操作,这时候命名线程是很实用的。如何做 为了演示如何确定正在运行的线程,我们创建了三个目标函数,并且引入了 time 在运行期间挂起2s,让结果更明显。 : import threading import
  • 2.5 如何实现一个线程
  • 使用threading模块实现一个新的线程,需要下面3步: 1.定义一个 Thread 类的子类 2.重写 __init__(self [,args]) 方法,可以添加额外的参数 3.最后,需要重写 run(self, [,args]) 方法来实现线
  • 2.6 使用Lock进行线程同步
  • 当两个或以上对共享内存的操作发生在并发线程中,并且至少有一个可以改变数据,又没有同步机制的条件下,就会产生竞争条件,可能会导致执行无效代码、bug、或异常行为。竞争条件最简单的解决方法是使用锁。锁的操作非常简单,当一个线程需要访问部分共享内存时,它必须先获得锁才能访问。此线程对这部分共享资源使用完成之后,该线程必须释放锁,然后其他线程就可以
  • 2.7 使用RLock进行线程同步
  • 如果你想让只有拿到锁的线程才能释放该锁,那么应该使用 RLock() 对象。和 Lock() 对象一样, RLock() 对象有两个方法: acquire() 和 release() 。当你需要在类外面保证线程安全,又要在类内使用同样方法的时候 RLock() 就很实用了。(译者注:RL
  • 2.8 使用信号量进行线程同步
  • 信号量由E.Dijkstra发明并第一次应用在操作系统中,信号量是由操作系统管理的一种抽象数据类型,用于在多线程中同步对共享资源的使用。本质上说,信号量是一个内部数据,用于标明当前的共享资源可以有多少并发读取。同样的,在threading模块中,信号量的操作有两个函数,即 acquir
  • 2.9 使用条件进行线程同步
  • 条件指的是应用程序状态的改变。这是另一种同步机制,其中某些线程在等待某一条件发生,其他的线程会在该条件发生的时候进行通知。一旦条件发生,线程会拿到共享资源的唯一权限。准备工作 解释条件机制最好的例子还是生产者-消费者问题。在本例中,只要缓存
  • 2.10 使用事件进行线程同步
  • 事件是线程之间用于通讯的对象。有的线程等待信号,有的线程发出信号。基本上事件对象都会维护一个内部变量,可以通过 set() 方法设置为 true ,也可以通过 clear() 方法设置为 false 。 wa
  • 2.11 使用with语法
  • Python从2.5版本开始引入了 with 语法。此语法非常实用,在有两个相关的操作需要在一部分代码块前后分别执行的时候,可以使用 with 语法自动完成。同事,使用 with 语法可以在特定的地方分配和释放资源,因此, with
  • 2.12 使用 queue 进行线程通信
  • 前面我们已经讨论到,当线程之间如果要共享资源或数据的时候,可能变的非常复杂。如你所见,Python的threading模块提供了很多同步原语,包括信号量,条件变量,事件和锁。如果可以使用这些原语的话,应该优先考虑使用这些
  • 2.13 评估多线程应用的性能
  • 在本节中,我们将验证GIL的影响,评估多线程应用的性能。前文已经介绍过,GIL是CPython解释器引入的锁,GIL在解释器层面阻止了真正的并行运行。解释器在执行任何线程之前,必须等待当前正在运行的线程释放GIL。事实上,解释器会强迫想要运行的线程必须拿到GI
  • 第三章 基于进程的并行
  • 3.1 介绍
  • 在之前的章节中,我们见识了如何用线程实现并发的应用。本章节将会介绍基于进程的并行。本章的重点将会集中在Python的 multiprocessing 和 mpi4py 这两个模块上。multiprocessing 是Pyt
  • 3.2 如何产生一个进程
  • "产生"(spawn)的意思是,由父进程创建子进程。父进程既可以在产生子进程之后继续异步执行,也可以暂停等待子进程创建完成之后再继续执行。Python的multiprocessing库通过以下几步创建进程:1.创建进程对象 2.调用 start() 方法,开启进程的活动3.调用 jo
  • 3.3 如何为一个进程命名
  • 在上一节的例子中,我们创建了一个进程,并为其分配了目标函数和函数变量。然而如果能给进程分配一个名字,那么debug的时候就更方便了。如何做 命名进程的方法和前一章中介绍的命名线程差不多(参考第二章,基于线程的并行,第四节,如何确定当前的线程)。下面的代码在主程序中创建了一个有名字的进程和一个没有名字的进程,目标函数都是 foo() 函数。 : # 命名一个进程
  • 3.4 如何在后台运行一个进程
  • 如果需要处理比较巨大的任务,又不需要人为干预,将其作为后台进程执行是个非常常用的编程模型。此进程又可以和其他进程并发执行。通过Python的multiprocessing模块的后台进程选项,我们可以让进程在后台运行。如何做
  • 3.5 如何杀掉一个进程
  • 我们可以使用 terminate() 方法立即杀死一个进程。另外,我们可以使用 is_alive() 方法来判断一个进程是否还存活。如何做 在本例中,创建一个目标函数为 foo() 的进程。启动之后,我们通过 terminate() 方法杀死它。 : # 杀死一个进程 import multiprocessing import timedef fo
  • 3.6 如何在子类中使用进程
  • 实现一个自定义的进程子类,需要以下三步: 1.定义 Process 的子类 2.覆盖 __init__(self [,args]) 方法来添加额外的参数 3.覆盖 run(self, [.args]) 方法来实现 Process 启动
  • 3.7 如何在进程之间交换对象
  • 并行应用常常需要在进程之间交换数据。Multiprocessing库有两个Communication Channel可以交换对象:队列(queue)和管道(pipe)。使用队列交换对象 我们可以通过队列数据结构来共享对象。Queue 返回一个进程共享的队列,是线程安全的,也是进程安全的。任何可序列化的对象(Python通过 pickable 模块序列化对象)都可以通过它进行交换
  • 3.8 进程如何同步
  • 多个进程可以协同工作来完成一项任务。通常需要共享数据。所以在多进程之间保持数据的一致性就很重要了。需要共享数据协同的进程必须以适当的策略来读写数据。相关的同步原语和线程的库很类似。进程的同步原理如下: Lock: 这个对象可以有两种装填:锁住的(locked)和没锁住的(unlocked)。一个Lock对象有两个方法, acquire() 和 re
  • 3.9 如何在进程之间管理状态
  • Python的多进程模块提供了在所有的用户间管理共享信息的管理者(Manager)。一个管理者对象控制着持有Python对象的服务进程,并允许其它进程操作共享对象。管理者有以下特性: 1.它控制着管理共享对象的服务进程2.它确保当某一进程修改了共享对象之后,所有的进程拿到额共享对象都得到了更新如何做 下面来看一个再进程之间共享对象
  • 3.10 如何使用进程池
  • 多进程库提供了 Pool 类来实现简单的多进程任务。 Pool 类有以下方法:1.apply(): 直到得到结果之前一直阻塞。 2.apply_async(): 这是 apply() 方法的一个变体,返回的是一个result对象。这是一个异步的操作,在所有的子类执行之前不会锁住主
  • 3.11 使用Python的mpi4py模块
  • Python 提供了很多MPI模块写并行程序。其中 mpi4py 是一个又有意思的库。它在MPI-1/2顶层构建,提供了面向对象的接口,紧跟C++绑定的 MPI-2。MPI的C语言用户可以无需学习新的接口就可以上手这个库。所以,它成为了Python中最广泛使用的MPI库。此模块包含的主要应用有:
  • 3.12 点对点通讯
  • MPI提供的最实用的一个特性是点对点通讯。两个不同的进程之间可以通过点对点通讯交换数据:一个进程是接收者,一个进程是发送者。Python的 mpi4py 通过下面两个函数提供了点对点通讯功能:1.Comm.Send(data, process_destination): 通过它在交流组中的排名
  • 3.13 避免死锁问题
  • 我们经常需要面临的一个问题是死锁,这是两个或多个进程都在阻塞并等待对方释放自己想要的资源的情况。 mpi4py 没有提供特定的功能来解决这种情况,但是提供了一些程序员必须遵守的规则,来避免死锁问题。如何做 让我们先分析下面的Python代码,下面的代码中介绍了一种典型的死锁问题;我们有两个进程,一个 rank 等于1,另一个 rank 等于5,他们互相通讯,并且每一个都有发送和接收的
  • 3.14 集体通讯:使用broadcast通讯
  • 在并行代码的开发中,我们会经常发现需要在多个进程间共享某个变量运行时的值,或操作多个进程提供的变量(可能具有不同的值)。为了解决这个问题,使用了通讯数。举例说,如果进程0要发送信息给进程1和进程2,同时也会发送信息给进程3,4,5,6,即使这些进程并不需要这些信息。另外,MPI库提供了在多个进程之间交换信息的方法,针对执行的机器做了优化。将所有进程变成通讯者的这种方法叫做集体交流。因此,一
  • 3.15 集体通讯:使用scatter通讯
  • scatter函数和广播很像,但是有一个很大的不同, comm.bcast 将相同的数据发送给所有在监听的进程, comm.scatter 可以将数据放在数组中,发送给不同的进程。下图展示了scatter的功能:comm.scatter 函数接收一个array,根据进程的rank将其中的元素发送给不同的进程。比如第一个元素将发送给进程0,第二个元素将发送给进程1,等等。 mpi4py 中
  • 3.16 集体通讯:使用gather通讯
  • gather 函数基本上是反向的 scatter ,即手机所有进程发送向root进程的数据。 mpi4py 实现的 gather 函数如下: recvbuf = comm.gather(sendbuf, rank_of_root_process) 这里, sendbuf 是要发送的数据, rank_of
  • 3.17 使用Alltoall通讯
  • Alltoall 集体通讯结合了 scatter 和 gather 的功能。在 mpi4py 中,有以下三种类型的 Alltoall 集体通讯。1.comm.Alltoall(sendbuf, recvbuf) : 2.comm.Alltoallv(sendbuf, recvbuf) :3.comm.Alltoallw
  • 3.18 简化操作
  • 同 comm.gather 一样, comm.reduce 接收一个数组,每一个元素是一个进程的输入,然后返回一个数组,每一个元素是进程的输出,返回给 root 进程。输出的元素中包含了简化的结果。在 mpi4py 中,我们将简化操作定义如下: :comm.Reduce(sendbuf, recvbuf,
  • 3.19 如何优化通讯
  • 拓扑是 MPI 提供的一个有趣功能。如前所述,所有通信功能(点对点或集体)都是指一组进程。我们一直使用包含所有进程的 MPI_COMM_WORLD 组。它为大小为n的通信组的每个进程分配 0 - n-1 的一个rank。但是,MPI允许我们为通信器分配虚拟拓扑。它为不同的进程定义了特定的标签分配。这种机制可以提高执行性能。实际上,如果构建虚拟拓扑,那么每个节点将只与其虚拟邻居进行通信
  • 第四章 异步编程
  • 4.1 介绍
  • 除了顺序执行和并行执行的模型之外,还有第三种模型,叫做异步模型,这是事件驱动模型的基础。异步活动的执行模型可以只有一个单一的主控制流,能在单核心系统和多核心系统中运行。在并发执行的异步模型中,许多任务被穿插在同一时间线上,所有的任务都由一个控制流执行(单一线程
  • 4.2 使用Python的 concurrent.futures 模块
  • Python3.2带来了 concurrent.futures 模块,这个模块具有线程池和进程池、管理并行编程任务、处理非确定性的执行流程、进程/线程同步等功能。此模块由以下部分组成: 1.concurrent.futures.Executor: 这是一个虚拟基类,提供了异步执行的方法。 2.submit(function, argument): 调度函数(可调用的对象)的执行,将 ar
  • 4.3 使用Asyncio管理事件循环
  • Python的Asyncio模块提供了管理事件、协程、任务和线程的方法,以及编写并发代码的原语。此模块的主要组件和概念包括: 1.事件循环: 在Asyncio模块中,每一个进程都有一个事件循环。 2.协程: 这是子程序的泛化概念。协程可以在执行期间暂停,这样就可以等待外部的处理(例如IO)完
  • 4.4 使用Asyncio管理协程
  • 在上文提到的例子中,我们看到当一个程序变得很大而且复杂时,将其划分为子程序,每一部分实现特定的任务是个不错的方案。子程序不能单独执行,只能在主程序的请求下执行,主程序负责协调使用各个子程序。协程就是子程序的泛化。和子程序一样的事,协程只负责计算任务的一步;和子程序不一样的是,协程没有主程序来进行调度。这是因为协程通过管道连接在一起,没有监视函数负责顺序调用它们。在协程中,执行
  • 4.5 使用Asyncio控制任务
  • Asyncio是用来处理事件循环中的异步进程和并发任务执行的。它还提供了 asyncio.Task() 类,可以在任务中使用协程。它的作用是,在同一事件循环中,运行某一个任务的同时可以并发地运行多个任务。当协程被包在任务中,它会自动将任务和事件循环连接起来,当事件循环启动的时候,任
  • 4.6 使用Asyncio和Futures
  • Asyncio 模块的另一个重要的组件是 Future 类。它和 concurrent.futures.Futures 很像,但是针对Asyncio的事件循环做了很多定制。 asyncio.Futures 类代表还未完成的结果(有可能是一个Exception)。所以综合来说,它
  • 第五章 分布式Python编程
  • 5.1 介绍
  • 分布式计算基本的思想是将一个大任务分散成几个小任务,交给分布式网络中的计算机去完成。在分布式计算的环境中,必须保证网络中的计算机的可用性(避免网络延迟、非预知的崩溃等)。所以就需要可以可持续的监控架构。采用这种技术产生的根本问题是对各种类型的流量(数据,任务,命令等)进行适当的分配。此外,还有一个分布式系统基础特征产生的问题:网络由不同操作系统的计算机组成,很多互不兼容。实际上,随着时间的
  • 5.2 使用Celery实现分布式任务
  • Celery 是一个 Python 框架,用来管理分布式任务的,遵循面向对象的中间件方法。它的主要 feature 是可以将许多小任务分布到一个大型的计算集群中,最后将任务的结果收集起来,组成整体的解决方案。要使用 Celery,我们需要下面几种组件: 1.Celery 模块(废
  • 5.3 如何使用Celery创建任务
  • 在本节中,我们将展示如何使用 Celery 模块创建一个任务。Celery 提供了下面的方法来调用任务: 1.apply_async(args[, kwargs[, ...]]): 发送一个任务消息 2.delay(*args, **kwargs): 发送一个任务消息的快捷方式,但是不支
  • 5.4 使用SCOOP进行科学计算
  • Scalable Concurrent Operations in Python (SCOOP) 是一个可扩展的 Python 并行计算库,可以将并行的任务(Python 的 Futures )放到各种各样的计算节点上执行。它基于 &
  • 5.5 通过 SCOOP 使用 map 函数
  • 当处理 list 或其他类型的序列时,一种很常用的操作是对序列中的每一个元素都执行相同的操作,然后收集结果。举例说,通过 Python IDLE 可以对一个 list 这样更新: : >>>items = [1,2,3,4,5,6,7,8,9,10] >>>updated_items = [] >>>for x in items:
  • 5.6 使用Pyro4进行远程方法调用
  • Python Remote Objects (Pyro4) 实现了类似 Java 的远程方法调用(Remote Method Invocation, RMI). 可以调用一个远程对象(存在于另一个进程中,甚至是另一台机器上),就像调用本地对象一样(处于和调用者一样的进程
  • 5.7 使用 Pyro4 链接对象
  • 在本章中,我们将展示如何使用 Pyro4 创建互相调用的对象链。假设我们想创建如下的分布式架构:如图所示,我们有四个对象:一个客户端,和依照三个链式拓扑配置的 Server。客户端将请求转发到 Server1 开始链式调用,然后转发到 Server2。然后调用对象链中的下一个对象 Server3. Server3 最后调用 Server1 结束。通过我们将要展示的这个例子
  • 5.8 使用Pyro4部署客户端-服务器应用
  • 在本节中,我们会用 Pyro4 学习如何写一个简单的客户端-服务器应用。这里提供的示例并不完整,但是可以成功运行。一个客户端-服务器程序就是,在一个网络内,客户端连接上服务器来请求特定的服务,可以与其他的客户端共享软件/硬件资源,并使用相同的协议。在本节的系统中,server 管理一个在线购物网站
  • 5.9 PyCSP和通信顺序进程
  • PyCSP 是基于通信顺序进程的一个 Python 模块。通信顺序进程是通过消息处理建立并发程序的编程范式。PyCSP 模块的特点是: 1.进程之间交换消息 2.线程之间可以共享内存 3.通过 channels 来实现交换消息 Channels 可以做
  • 5.10 使用RPyC远程调用
  • Remote Python Call(RPyC)是一个用作远程过程调用,同时也可以用作分布式计算的Python模块。其基础RPC主要是提供一种将控制从当前程序(客户端)转移到其他程序(服务器)的机制,类似于在一个主程序里去调用一个子程序。这种方式的优点是它拥有非常简单的语义,知识以及熟悉的集中式函数调用。在一个程序调用里, 客户端进程会挂起,直到服务器完成计算返回结果后
读者评论
最近这些人在读这本书