/ 中存储网

7 个用于并行处理的 Python 库

2023-09-17 19:13:17 来源:中存储网

Python 非常方便,对程序员也很友好,但它并不是速度最快的编程语言。Python 的一些速度限制是由于其默认实现 CPython 是单线程的。也就是说,CPython 一次不会使用超过一个硬件线程。

虽然您可以使用 Python 内置的线程模块来加快速度,但线程只能提供并发性,而不是并行性。它适用于运行不依赖 CPU 的多个任务,但对于加速每个任务都需要一个完整 CPU 的多个任务却无能为力。这种情况将来可能会改变,但目前最好假设 Python 中的线程不会带来并行性。

Python 确实包含一种在多个 CPU 上运行工作负载的本地方法。多处理模块会启动 Python 解释器的多个副本,每个副本都在一个单独的内核上,并提供了在内核间拆分任务的原语。但有时,即使是多进程也是不够的。

在某些情况下,工作不仅需要在多个内核上分配工作,还需要在多台机器上分配工作。这就是本文介绍的 Python 库和框架的用武之地。以下是您可以用来将现有 Python 应用程序及其工作负载分散到多核、多机或两者上的七个框架。

  1. Ray
  2. Dask
  3. Dispy
  4. Pandaral·lel
  5. Ipyparallel
  6. Joblib
  7. Parsl

Ray

由加州大学伯克利分校的一个研究团队开发,是许多分布式机器学习库的基础。但是,Ray 并不局限于机器学习任务,即使这是它最初的用途。您可以使用 Ray 将任何类型的 Python 任务分解并分布到多个系统中。

Ray 的语法非常简单,因此你不需要对现有的应用程序进行大量的修改就能实现并行化。@ray.remote 装饰器会将函数分发到 Ray 集群中的任何可用节点,并可选择指定使用多少 CPU 或 GPU 的参数。每个分布式函数的结果都会以 Python 对象的形式返回,因此易于管理和存储,节点间或节点内的复制量也很小。例如,在处理 NumPy 数组时,最后一项功能就会派上用场。

Ray 甚至内置了集群管理器,可以根据需要在本地硬件或流行的云计算平台上自动启动节点。其他 Ray 库还能让你扩展常见的机器学习和数据科学工作负载,因此你不必手动为它们搭建脚手架。例如,Ray Tune 可让您为大多数常见的机器学习系统(PyTorch 和 TensorFlow 等)大规模地进行超参数转换。

Dask

从外观上看,Dask 很像 Ray。它也是一个用 Python 进行分布式并行计算的库,有自己的任务调度系统,能识别 NumPy 等 Python 数据框架,并能从一台机器扩展到多台机器。

Dask 和 Ray 的一个关键区别在于调度机制。Dask 使用集中式调度器处理集群的所有任务。Ray 则是分散式的,这意味着每台机器都运行自己的调度程序,因此任何调度任务的问题都是在单台机器的层面上处理的,而不是整个集群。Dask 的任务框架与 Python 的原生并发期货接口协同工作,因此对于使用过该库的人来说,大部分关于作业如何工作的隐喻应该都不陌生。

Dask 有两种基本工作方式。第一种是并行化数据结构,即 Dask 自己版本的 NumPy 数组、列表或 Pandas DataFrames。将这些结构的 Dask 版本换成默认版本,Dask 就会自动在集群中分散执行。这通常只需要更改导入的名称,但有时可能需要重写才能完全运行。

第二种方法是通过 Dask 的底层并行化机制,包括函数装饰器,将作业分散到各个节点,并同步("立即 "模式)或异步("懒惰 "模式)返回结果。这两种模式可根据需要混合使用。

Dask 还提供了一种称为角色的功能。角色是指向另一个 Dask 节点上的作业的对象。这样,需要大量本地状态的作业就可以就地运行,并被其他节点远程调用,因此作业的状态无需复制。Ray 缺乏类似 Dask 的演员模型,无法支持更复杂的作业分发。不过,Desk 的调度器并不知道行动者在做什么,所以如果行动者乱跑或挂起,调度器也无法干预。文档中是这么说的:"性能高,但不灵活",因此在使用角色时应小心谨慎。

Dispy

通过 Dispy,你可以将整个 Python 程序或单个函数分发到机器集群中并行执行。它使用平台本地的网络通信机制来保持快速高效,因此 Linux、macOS 和 Windows 机器都能很好地运行。因此,与本文讨论的其他解决方案相比,Python 是一种更通用的解决方案,如果你需要的不是专门用于加速机器学习任务或特定数据处理框架的解决方案,那么 Python 值得你一试。

Dispy 的语法与多进程有点类似,你需要明确创建一个集群(多进程则需要创建一个进程池),向集群提交工作,然后检索结果。为使用 Dispy 而修改作业可能需要更多的工作,但你也可以精确控制作业的派发和返回方式。例如,你可以返回临时或部分完成的结果,在作业分发过程中传输文件,以及在传输数据时使用 SSL 加密。

Pandaral·lel

顾名思义,Pandaral-lel 是一种在多个节点上并行处理 Pandas 作业的方法。缺点是 Pandaral-lel 只适用于 Pandas。但是,如果你使用的是 Pandas,而且你需要的只是一种在单台计算机上跨多个内核加速 Pandas 作业的方法,那么 Pandaral-lel 就能很好地完成任务。

需要注意的是,虽然 Pandaral-lel 可以在 Windows 上运行,但它只能在 Windows Linux 子系统启动的 Python 会话中运行。Linux 和 macOS 用户可以原样运行 Pandaral-lel。

Ipyparallel

Ipyparallel 是另一款专注于多处理和任务分配的系统,专门用于在集群中并行执行 Jupyter 笔记本代码。已经使用 Jupyter 的项目和团队可以立即开始使用 Ipyparallel。

Ipyparallel 支持多种代码并行化方法。最简单的是 map,它可以将任何函数应用到序列中,并将工作平均分配到可用的节点上。对于更复杂的工作,你可以装饰特定函数,使其始终远程或并行运行。

Jupyter 笔记本支持 "神奇命令",用于执行只有在笔记本环境中才能执行的操作。Ipyparallel 添加了一些自己的神奇命令。例如,你可以在任何 Python 语句前加上 %px 来自动将其并行化。

Joblib

Joblib 有两个主要目标:并行运行作业,如果没有任何变化,则不重新计算结果。这些效率使 Joblib 非常适合科学计算,因为在科学计算中,可重现的结果是神圣不可侵犯的。Joblib 的文档为如何使用其所有功能提供了大量示例。

用于并行化工作的 Joblib 语法非常简单--相当于一个装饰器,可用于在处理器间拆分作业或缓存结果。并行作业可以使用线程或进程。

Joblib 包含一个透明的磁盘缓存,用于缓存计算作业创建的 Python 对象。如上所述,该缓存不仅能帮助 Joblib 避免重复工作,还能用于暂停和恢复长期运行的作业,或在作业崩溃后从中断的地方重新开始。缓存还针对 NumPy 数组等大型对象进行了智能优化。通过使用 numpy.memmap,同一系统中的进程可以共享内存中的数据区域。这一切使得 Joblib 对于可能需要很长时间才能完成的工作非常有用,因为你可以避免重做现有工作,并在需要时暂停/恢复。

Joblib 没有提供在多台独立计算机上分配作业的方法。理论上,可以使用 Joblib 的管道来实现这一功能,但使用其他原生支持该功能的框架可能会更简单。

Parsl

Parsl 是 "并行脚本库 "的缩写,它允许你使用与 Python 现有 Pool 对象大致相同的语法,将计算任务分拆到多个系统中。它还能让你将不同的计算任务拼接成多步骤工作流,这些工作流可以并行、依次或通过 map/reduce 操作运行。

Parsl 不仅能让你执行本地 Python 应用程序,还能通过对 shell 下达命令的方式运行任何其他外部应用程序。你的 Python 代码就像普通的 Python 代码一样,只需使用一个特殊的函数装饰器来标记工作的入口点。作业提交系统还能让您对目标上的运行方式进行细粒度控制--例如,每个 Worker 的内核数量、每个 Worker 的内存容量、CPU 亲和性控制、超时轮询频率等。

Parsl 提供的一项出色功能是一套预制模板,可将工作分派到各种高端计算资源。这不仅包括 AWS 或 Kubernetes 集群等主力资源,还包括 Blue Waters、ASPIRE 1、Frontera 等超级计算资源(前提是你有访问权限)。(Parsl 的共同开发得到了许多构建此类硬件的机构的帮助)。

总结

Python 在线程方面的限制将继续发展,计划进行的重大修改将允许线程并行运行,以处理占用 CPU 的工作。但这些更新离实际可用还有好几年的时间。在我们等待的时候,专为并行设计的库可以帮助我们填补空白。