我要投搞

标签云

收藏小站

爱尚经典语录、名言、句子、散文、日志、唯美图片

当前位置:多盈娱乐 > 多进程 >

取代Python多进程!伯克利开源分布式框架Ray

归档日期:04-24       文本归类:多进程      文章编辑:爱尚语录

  Ray 由伯克利开源,是一个用于并行计算和分布式 Python 开发的开源项目。本文将介绍如何使用 Ray 轻松构建可从笔记本电脑扩展到大型集群的应用程序。

  并行和分布式计算是现代应用程序的主要内容。我们需要利用多个核心或多台机器来加速应用程序或大规模运行它们。网络爬虫和搜索所使用的基础设施并不是在某人笔记本电脑上运行的单线程程序,而是相互通信和交互的服务的集合。

  很多教程解释了如何使用 Python 的多进程模块()。遗憾的是,多进程模块在处理现代应用程序的要求方面存在严重的短板。这些要求包括以下这些内容:

  必要的概念传统编程依赖于两个核心概念:函数和类。使用这些构建块就可以构建出无数的应用程序。

  一方面,OpenMPI、Python 多进程和 ZeroMQ 等工具提供了用于发送和接收消息的低级原语。这些工具非常强大,但它们提供了不同的抽象,因此要使用它们就必须从头开始重写单线程应用程序。

  另一方面,我们也有一些特定领域的工具,例如用于模型训练的 TensorFlow、用于数据处理且支持 SQL 的 Spark,以及用于流式处理的 Flink。这些工具提供了更高级别的抽象,如神经网络、数据集和流。但是,因为它们与用于串行编程的抽象不同,所以要使用它们也必须从头开始重写应用程序。

  Ray 占据了一个独特的中间地带。它并没有引入新的概念,而是采用了函数和类的概念,并将它们转换为分布式的任务和 actor。Ray 可以在不做出重大修改的情况下对串行应用程序进行并行化。

  用于将“任务”分配给 worker(以及其他计算机)的调度程序进程。任务是 Ray 调度的工作单元,对应于一个函数调用或方法调用。

  共享内存对象存储库,用于在 worker 之间有效地共享对象(无需创建副本)。

  Ray worker 是独立的进程,而不是线程,因为在 Python 中存在全局解释器锁,所以对多线程的支持非常有限。

  要将 Python 函数 f 转换为一个“远程函数”(可以远程和异步执行的函数),可以使用 @ray.remote 装饰器来声明这个函数。然后函数调用 f.remote() 将立即返回一个 future(future 是对最终输出的引用),实际的函数执行将在后台进行(我们将这个函数执行称为任务)。

  因为对 f.remote(i) 的调用会立即返回,所以运行这行代码四次就可以并行执行 f 的四个副本。

  一个任务还可以依赖于其他任务。在下面的代码中,multiply_matrices 任务依赖两个 create_matrix 任务的输出,因此在执行前两个任务之前它不会先执行。前两个任务的输出将自动作为参数传给第三个任务,future 将被替换为相应的值。通过这种方式,任务可以按照任意的 DAG 依赖关系组合在一起。

  我们可以以更复杂的方式使用任务依赖。例如,假设我们希望将 8 个值聚合在一起。在我们的示例中,我们将进行整数加法,但在很多应用程序中,跨多台计算机聚合大型向量可能会造成性能瓶颈。在这个时候,只要修改一行代码就可以将聚合的运行时间从线性降为对数级别,即聚合值的数量。

  左侧的依赖图深度为 7,右侧的依赖图深度为 3。计算产生相同的结果,但右侧的依赖图执行得更快。

  如上所述,要将一个任务的输出作为输入提供给后续任务,只需将第一个任务返回的 future 作为参数传给第二个任务。Ray 的调度程序会自动考虑任务依赖关系。在第一个任务完成之前不会执行第二个任务,第一个任务的输出将自动被发送给执行第二个任务的机器。

  上面的代码非常清晰,但请注意,这两种方法都可以使用 while 循环来实现,这种方式更为简洁。

  更简洁的聚合实现方案。两个代码块之间的唯一区别是“add.remote”的输出是放在列表的前面还是后面。

  在不使用类的情况下开发有趣的应用程序很具挑战性,在分布式环境中也是如此。

  你可以使用 @ray.remote 装饰器声明一个 Python 类。在实例化类时,Ray 会创建一个新的“actor”,这是一个运行在集群中并持有类对象副本的进程。对这个 actor 的方法调用转变为在 actor 进程上运行的任务,并且可以访问和改变 actor 的状态。通过这种方式,可以在多个任务之间共享可变状态,这是远程函数无法做到的。

  各个 actor 按顺序执行方法(每个方法都是原子方法),因此不存在竞态条件。可以通过创建多个 actor 来实现并行性。

  在上面的示例中,我们只在主 Python 脚本中调用 actor 的方法。actor 的一个最强大的地方在于我们可以将句柄传给它,让其他 actor 或其他任务都调用同一 actor 的方法。

  以下示例创建了一个可以保存消息的 actor。几个 worker 任务反复将消息推送给 actor,主 Python 脚本定期读取消息。

本文链接:http://ayraswimwear.com/duojincheng/75.html