标签分类
当前位置:首页 > 程序设计电子书 > Python编程电子书网盘下载
Python并行编程参考手册 Python并行编程参考手册
jack4096

jack4096 提供上传

资源
37
粉丝
15
喜欢
176
评论
10

    Python并行编程参考手册 PDF 原书影印版

    Python编程电子书
    • 发布时间:

    给大家带来的一篇关于Python编程相关的电子书资源,介绍了关于Python、并行编程、手册、Python并行编程方面的内容,本书是由东南大学出版社出版,格式为PDF,资源大小41.4 MB,吉安卡洛·扎克尼编写,目前豆瓣、亚马逊、当当、京东等电子书综合评分为:8.2,更多相关的学习资源可以参阅 程序设计电子书Python电子书Python视频、等栏目。

  • Python并行编程参考手册 PDF 下载
  • 下载地址:https://pan.baidu.com/s/1Xkb0elAshy-jMdYKbP2bmg
  • 分享码:a6z8
  • Python并行编程参考手册

    内容介绍

    若要灵活运用全部的计算资源来搭建高效率的系统软件,并行编程技术是必不可少的这项专业技能。《python并行编程手册》以PHP为蓝本,对并行编程行业的各类技术性与专业知识开展了普遍且深层次的解读。根据对这书的学习培训,小读者将可以迅速且精确地把握并行编程各个方面的专业技能,进而运用在自个的新项目开发设计中,提高系统软件运作高效率。

    《python 并行编程手册》共分成6章,从基本原理到实践活动专业化地对并行编程技术开展了逐层分析,并根据很多可运作的案例演试了每1个知识结构图的主要应用方法,是提高并行编程专业技能的二本难能可贵的好书。坚信《python 并行编程手册》的出版发行将会弥补PHP在并行编程行业运用的一整空白页,可以协助愿意从业并行编程与并行计算的小读者提高实践活动工作能力,并将这种工作能力运用到实际上的新项目开发设计中。

    目录

    • 1 并行计算与Python起步 1
    • 2 基于线程的并行. .27
    • 3 基于进程的并行63
    • 4 异步编程. 111
    • 5 分布式Python133
    • 6 使用Python进行GPU编程. 175

    读书笔记

    Python并行分布式框架Celery详解

    Celery 简介

    除了redis,还可以使用另外一个神器---Celery。Celery是一个异步任务的调度工具。

    Celery 是 Distributed Task Queue,分布式任务队列,分布式决定了可以有多个 worker 的存在,队列表示其是异步操作,即存在一个产生任务提出需求的工头,和一群等着被分配工作的码农。

    在 Python 中定义 Celery 的时候,我们要引入 Broker,中文翻译过来就是“中间人”的意思,在这里 Broker 起到一个中间人的角色。在工头提出任务的时候,把所有的任务放到 Broker 里面,在 Broker 的另外一头,一群码农等着取出一个个任务准备着手做。

    这种模式注定了整个系统会是个开环系统,工头对于码农们把任务做的怎样是不知情的。所以我们要引入 Backend 来保存每次任务的结果。这个 Backend 有点像我们的 Broker,也是存储任务的信息用的,只不过这里存的是那些任务的返回结果。我们可以选择只让错误执行的任务返回结果到 Backend,这样我们取回结果,便可以知道有多少任务执行失败了。

    Celery(芹菜)是一个异步任务队列/基于分布式消息传递的作业队列。它侧重于实时操作,但对调度支持也很好。Celery用于生产系统每天处理数以百万计的任务。Celery是用Python编写的,但该协议可以在任何语言实现。它也可以与其他语言通过webhooks实现。Celery建议的消息队列是RabbitMQ,但提供有限支持Redis, Beanstalk, MongoDB, CouchDB, 和数据库(使用SQLAlchemy的或Django的 ORM) 。

    Celery是易于集成Django, Pylons and Flask,使用 django-celery, celery-pylons and Flask-Celery 附加包即可。

    在学习Celery之前,我先简单的去了解了一下什么是生产者消费者模式。

    生产者消费者模式

    在实际的软件开发过程中,经常会碰到如下场景:某个模块负责产生数据,这些数据由另一个模块来负责处理(此处的模块是广义的,可以是类、函数、线程、进程等)。产生数据的模块,就形象地称为生产者;而处理数据的模块,就称为消费者。

    单单抽象出生产者和消费者,还够不上是生产者消费者模式。该模式还需要有一个缓冲区处于生产者和消费者之间,作为一个中介。生产者把数据放入缓冲区,而消费者从缓冲区取出数据,如下图所示:

    Python并行分布式框架Celery详解

    生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过消息队列(缓冲区)来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给消息队列,消费者不找生产者要数据,而是直接从消息队列里取,消息队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。这个消息队列就是用来给生产者和消费者解耦的。------------->这里又有一个问题,什么叫做解耦?

    解耦

    假设生产者和消费者分别是两个类。如果让生产者直接调用消费者的某个方法,那么生产者对于消费者就会产生依赖(也就是耦合)。将来如果消费者的代码发生变化,可能会影响到生产者。而如果两者都依赖于某个缓冲区,两者之间不直接依赖,耦合也就相应降低了。生产者直接调用消费者的某个方法,还有另一个弊端。由于函数调用是同步的(或者叫阻塞的),在消费者的方法没有返回之前,生产者只好一直等在那边。万一消费者处理数据很慢,生产者就会白白糟蹋大好时光。缓冲区还有另一个好处。如果制造数据的速度时快时慢,缓冲区的好处就体现出来了。当数据制造快的时候,消费者来不及处理,未处理的数据可以暂时存在缓冲区中。等生产者的制造速度慢下来,消费者再慢慢处理掉。

    因为太抽象,看过网上的说明之后,通过我的理解,我举了个例子:吃包子。

    假如你非常喜欢吃包子(吃起来根本停不下来),今天,你妈妈(生产者)在蒸包子,厨房有张桌子(缓冲区),你妈妈将蒸熟的包子盛在盘子(消息)里,然后放到桌子上,你正在看巴西奥运会,看到蒸熟的包子放在厨房桌子上的盘子里,你就把盘子取走,一边吃包子一边看奥运。在这个过程中,你和你妈妈使用同一个桌子放置盘子和取走盘子,这里桌子就是一个共享对象。生产者添加食物,消费者取走食物。桌子的好处是,你妈妈不用直接把盘子给你,只是负责把包子装在盘子里放到桌子上,如果桌子满了,就不再放了,等待。而且生产者还有其他事情要做,消费者吃包子比较慢,生产者不能一直等消费者吃完包子把盘子放回去再去生产,因为吃包子的人有很多,如果这期间你好朋友来了,和你一起吃包子,生产者不用关注是哪个消费者去桌子上拿盘子,而消费者只去关注桌子上有没有放盘子,如果有,就端过来吃盘子中的包子,没有的话就等待。对应关系如下图:

    Python并行分布式框架Celery详解

    考察了一下,原来当初设计这个模式,主要就是用来处理并发问题的,而Celery就是一个用python写的并行分布式框架。

    然后我接着去学习Celery

    Celery 是一个强大的 分布式任务队列 的 异步处理框架,它可以让任务的执行完全脱离主程序,甚至可以被分配到其他主机上运行。我们通常使用它来实现异步任务(async task)和定时任务(crontab)。我们需要一个消息队列来下发我们的任务。首先要有一个消息中间件,此处选择rabbitmq (也可选择 redis 或 Amazon Simple Queue Service(SQS)消息队列服务)。推荐 选择 rabbitmq 。使用RabbitMQ是官方特别推荐的方式,因此我也使用它作为我们的broker。

    Celery的定义

    Celery(芹菜)是一个简单、灵活且可靠的,处理大量消息的分布式系统,并且提供维护这样一个系统的必需工具。

    我比较喜欢的一点是:Celery支持使用任务队列的方式在分布的机器、进程、线程上执行任务调度。然后我接着去理解什么是任务队列。

    任务队列

    任务队列是一种在线程或机器间分发任务的机制。

    消息队列

    消息队列的输入是工作的一个单元,称为任务,独立的职程(Worker)进程持续监视队列中是否有需要处理的新任务。

    Celery 用消息通信,通常使用中间人(Broker)在客户端和职程间斡旋。这个过程从客户端向队列添加消息开始,之后中间人把消息派送给职程,职程对消息进行处理。如下图所示:

    Python并行分布式框架Celery详解

    Celery 系统可包含多个职程和中间人,以此获得高可用性和横向扩展能力。

    Celery的架构

    Celery的架构由三部分组成,消息中间件(message broker),任务执行单元(worker)和任务执行结果存储(task result store)组成。

    消息中间件

    Celery本身不提供消息服务,但是可以方便的和第三方提供的消息中间件集成,包括,RabbitMQ,Redis,MongoDB等,这里我先去了解RabbitMQ,Redis。

    linux安装redis参考:https://www.jb51.net/article/146751.htm

    docker 安装redis参考://www.jb51.net/article/148880.htm

    docker安装rabbitmq参考:https://www.jb51.net/article/144748.htm

    任务执行单元

    Worker是Celery提供的任务执行的单元,worker并发的运行在分布式的系统节点中

    任务结果存储

    Task result store用来存储Worker执行的任务的结果,Celery支持以不同方式存储任务的结果,包括Redis,MongoDB,Django ORM,AMQP等,这里我先不去看它是如何存储的,就先选用Redis来存储任务执行结果。

    然后我接着去安装Celery,在安装Celery之前,我已经在自己虚拟机上安装好了Python,版本是3.6,

    安装celery,版本为4.2.1

    sudo apt install python-celery-common

    因为涉及到消息中间件,所以我先去选择一个在我工作中要用到的消息中间件(在Celery帮助文档中称呼为中间人<broker>),为了更好的去理解文档中的例子,我安装了两个中间件,一个是RabbitMQ,一个redis。

    在这里我就先根据Celery的帮助文档安装和设置RabbitMQ。要使用 Celery,我们需要创建一个 RabbitMQ 用户、一个虚拟主机,并且允许这个用户访问这个虚拟主机。下面是我在个人pc机Ubuntu16.04上的设置:

    $ sudo rabbitmqctl add_user forward password

    #创建了一个RabbitMQ用户,用户名为forward,密码是password

    $ sudo rabbitmqctl add_vhost ubuntu

    #创建了一个虚拟主机,主机名为ubuntu

    $ sudo rabbitmqctl set_permissions -p ubuntu forward ".*" ".*" ".*"

    #允许用户forward访问虚拟主机ubuntu,因为RabbitMQ通过主机名来与节点通信

    $ sudo rabbitmq-server

    之后我启用RabbitMQ服务器,结果如下,成功运行:

    Python并行分布式框架Celery详解

    之后我安装Redis,它的安装比较简单,如下:

    $ sudo pip install redis

    然后进行简单的配置,只需要设置 Redis 数据库的位置:

    BROKER_URL = 'redis://localhost:6379/0'

    URL的格式为:

    redis://:password**@hostname**:port/db_number

    URL Scheme 后的所有字段都是可选的,并且默认为 localhost 的 6379 端口,使用数据库 0。我的配置是:

    redis://:password**@ubuntu**:6379/5

    之后安装Celery,我是用标准的Python工具pip安装的,如下:

    $ sudo pip install celery

    开始使用 Celery

    使用celery包含三个方面:1. 定义任务函数。2. 运行celery服务。3. 客户应用程序的调用。

    为了测试Celery能否工作,我运行了一个最简单的任务,编写tasks.py:

    from celery import Celery
    # broker设置中间件,backend设置后端存储
    app = Celery('tasks',broker='redis://127.0.0.1:6379/5',backend='redis://127.0.0.1:6379/6')
    @app.task
    def add(x,y):
      return x+y

    编辑保存退出后,我在当前目录下运行如下命令(记得要先开启redis):

    $ celery -A tasks worker --loglevel=info

    启动一个worker

    #查询文档,了解到该命令中-A参数表示的是Celery APP的名称,这个实例中指的就是tasks.py(和文件名一致),后面的tasks就是APP的名称,worker是一个执行任务角色,后面的loglevel=info记录日志类型默认是info,这个命令启动了一个worker,用来执行程序中add这个加法任务(task)。

    然后看到界面显示结果如下:

    Python并行分布式框架Celery详解

    我们可以看到Celery正常工作在名称luanpeng-XPS15R的虚拟主机上,版本为v4.2.1,在下面的[config]中我们可以看到当前APP的名称tasks,运输工具transport就是我们在程序中设置的中间人redis://127.0.0.1:6379/5,result我们没有设置,暂时显示为disabled,然后我们也可以看到worker缺省使用perfork来执行并发,当前并发数显示为1,然后可以看到下面的[queues]就是我们说的队列,当前默认的队列是celery,然后我们看到下面的[tasks]中有一个任务tasks.add.

    如果你有多个不同类型的任务可以放在不同的文件夹下,比如我们在在app1文件夹创建一个tasks.py,在app2文件夹下创建一个tasks.py

    我们可以这样定义任务

    celery -A app1.tasks worker --loglevel=info

    注意:目录结构和命令发起的当前目录决定了任定义时的命令,任务定义的命令决定了任务定义的名称,任务的名称决定了任务调用时的名称。

    了解了这些之后,根据文档在当前目录,我重新打开一个terminal,然后执行Python,进入Python交互界面,用delay()方法调用任务,执行如下操作:

    如果我们只有一个tasks.py文件,我们可以这样定义任务

    celery -A tasks worker --loglevel=info

    那我们可以这样调用任务start_task.py,py文件必须和tasks.py文件在同一个目录下

    from tasks import add
    add.delay(6,6)  # 调用delay函数即可执行任务

    如果我们在app1文件夹下有tasks.py文件,我们可以这样定义任务

    celery -A app1.tasks worker --loglevel=info

    那我们可以这样调用任务start_task.py

    from app1.tasks import add
    add.delay(6,6)  # 调用delay函数即可执行任务

    所以定义任务和调用任务必须在同一个目录。

    执行调用任务的start_task.py文件

    python start_task.py

    这个任务已经由之前启动的Worker异步执行了,然后我打开之前启动的worker的控制台,对输出进行查看验证,结果如下:

    [2018-09-24 20:07:11,496: INFO/MainProcess] Received task: app1.tasks.add[8207c280-0864-4b1e-8792-155de5417406] 
    [2018-09-24 20:07:11,501: INFO/ForkPoolWorker-4] Task app1.tasks.add[8207c280-0864-4b1e-8792-155de5417406] succeeded in 0.003930353002942866s: 12

    第一行说明worker收到了一个任务:app1.tasks.add,这里我们和之前发送任务返回的AsyncResult对比我们发现,每个task都有一个唯一的ID,第二行说明了这个任务执行succeed,执行结果为12。

    查看资料说调用任务后会返回一个AsyncResult实例,可用于检查任务的状态,等待任务完成或获取返回值(如果任务失败,则为异常和回溯)。但这个功能默认是不开启的,需要设置一个 Celery 的结果后端(backend),也就是tasks.py设置的使用redis进行结果存储。

    通过这个例子后我对Celery有了初步的了解,然后我在这个例子的基础上去进一步的学习。

    因为Celery是用Python编写的,所以为了让代码结构化一些,就像一个应用

    Python并行分布式框架Celery详解

    app1/app1_app.py

    from celery import Celery
    import os,io
    # 在app1目录同级目录执行celery -A app1.app1_app worker -l info
    app = Celery(main='app1.app1_app',include=['app1.tasks1','app1.tasks2']) # 创建app,并引入任务定义。main、include参数的值为模块名,所以都是指定命令的相对目录
    app.config_from_object('app1.app1_config')  # 通过配置文件进行配置,而着这里是相对目录
    # broker设置中间件,backend设置后端存储
    # app = Celery('app1.app1_app',broker='redis://127.0.0.1:6379/5',backend='redis://127.0.0.1:6379/6',include=['app1.tasks1','app1.task2'])
    if __name__ == "__main__":
      log_path = os.getcwd()+'/log/celery.log'
      if(not os.path.exists(log_path)):
        f = open(log_path, 'w')
        f.close()
      # 在app1目录同级目录执行celery -A app1.app1_app worker -l info
      app = Celery(main='app1_app',include=['tasks1', 'tasks2']) # 创建app,并引入任务定义。main、include参数的值为模块名,所以都是指定命令的相对目录
      app.config_from_object('app1_config') # 通过配置文件进行配置,而着这里是相对目录
      # 使用下面的命令也可以启动celery,不过要该模块的名称,是的相对目录正确
      app.start(argv=['celery', 'worker', '-l', 'info', '-f', 'log/celery.log', "-c", "40"])
    
    

    一定要注意模块的相对目录,和你想要执行命令的目录

    #首先创建了一个celery实例app,实例化的过程中,制定了任务名(也就是包名.模块名),Celery的第一个参数是当前模块的名称,我们可以调用config_from_object()来让Celery实例加载配置模块,我的例子中的配置文件起名为app1_config.py,配置文件如下: