这项工作由 Continuum AnalyticsXDATA Program 支持,作为 Blaze Project 的一部分

tl;dr: Dask 昨天满一岁了。我们讨论了成功和失败之处。

Dask 于一年前的昨天始于 以下提交 (此处略有编辑以求清晰)。

def istask(x):
    return isinstance(x, tuple) and x and callable(x[0])


def get(d, key):
    v = d[key]
    if istask(v):
        func, args = v[0], v[1:]
        return func(*[get(d, arg) for arg in args])
    else:
        return v

 ... (and around 50 lines of tests)

这是一个非常低效的调度器

从那时起,dask 已经成熟,扩展到新的领域,汇聚了优秀的开发者,并催生了其他开源项目。我认为现在是回顾过去哪些做得好、哪些做得不好以及未来应该努力的方向的好时机。

集合

大多数用户通过 dask.array/bag/dataframe/imperative 这些高级集合来体验 dask。它们各自发展,拥有不同的用户群和不同的成熟度。

dask.array

并行处理大于内存数组的模块 dask.array 在 dask 组件中取得了最大的成功。它是最古老、最成熟、最复杂的子项目。dask.array 的大部分用途来自下游项目,特别是 xray,它似乎在气候科学领域大受欢迎。Dask.array 在图像处理、基因组学和数值算法研究中也得到了相当多的应用。

现在我认识或不认识的人都使用 dask.array 进行科学研究。从我的角度来看,这算是任务完成了。

算法上仍然需要调整,尤其是在扩展到分布式系统时(详见下文)。

dask.bag

Dask.bag 最初是一个周末项目,之后没有太大发展。幸运的是,它的工作量不大,这个子模块可能具有最高的价值/投入比。

然而,Bag 没有像它的老大哥 array 那样受到太多关注。它很方便,但用得不如 array 多,因此也不那么健壮。

dask.dataframe

Dataframe 是一个有趣的案例,它既相当复杂、相当成熟,同时可能也是最让用户感到沮丧的。

Dask.dataframe 通过利用 Pandas 获得了巨大的价值,既包括底层(一个 dask DataFrame 是许多 pandas DataFrames 的集合),也包括复制其 API(Pandas 用户无需学习新 API 即可使用 dask.dataframe)。然而,由于 dask.dataframe 只实现了 Pandas 的一个核心子集,用户最终会遇到功能缺失的问题。

这可以分解为以下几个问题

  1. 目前尚不清楚是否存在一个能够处理大多数用例的 Pandas 核心子集。用户在一个工作流程中会触及 Pandas 的许多分散的部分。一个用户认为是核心的功能,另一个用户可能认为是边缘功能。很难确定需要实现一个什么样的足够子集。
  2. 一旦你实现了这个子集(并且我们已经尽力了),很难向用户传达关于哪些功能可用、哪些功能不可用的期望。

尽管如此,dask.dataframe 还是相当可靠的。它非常快速、富有表现力,并且能够很好地处理常见用例。它可能在 StackOverflow 上产生了最多的问题。这既表明了用户的困惑,也表明了它的活跃使用。

在此特别感谢 Jeff Reback,他促使 Pandas 释放了 GIL;以及 Masaaki Horikoshi (@sinhrks),他极大地提高了 dask.dataframe 的成熟度。

dask.imperative

也被称为 dask.do,这个小小的后端仍然是最强大且(除了我之外)使用最少的工具之一。我们应该重新考虑这里的 API 并改进学习材料。

关于集合的一些总体思考

警告:本节内容相当主观

大数据集合很酷,但可能不像人们预期的那么有用。并行应用程序通常比简单地用大型数组或大型数据框来描述要复杂得多。许多实际的并行计算最终对并行性有着更特殊的需求。这并不是说数组和数据框抽象对于并行计算不重要,只是我们不应仅限于它们。世界是更复杂的。

然而,在特定领域内打破“世界是复杂的”这一规则是合理的。NDArrays 在气候科学中似乎运作良好。像 Dato 的 SFrame 这样的专用大型数据框对于特定类别的机器学习算法似乎很有效。SQL 表无疑是商业智能领域中有效的抽象。大型集合在特定环境中很有用,但它们可能受到了过多的关注。尤其是大型数据框,被过度吹捧了。

我看到的用 dask 完成的真正新颖和令人印象深刻的工作,大多数都是通过自定义图或使用 dask.imperative API 完成的。我认为我们应该考虑提供能让用户更容易表达自定义算法的 API。

避免并行化

在进行关于并行化的演讲时,我开始加入一个简短的“避免并行化”部分。从我在 Stack Overflow 上看到的问题以及与人们在遇到性能挑战时的普遍交流来看,他们的第一个解决方案似乎总是并行化。这是次优的选择。改进存储格式、使用更好的算法或使用 C/Numba 加速的代码通常比并行化便宜得多。不幸的是,存储格式和 C 没有大数据并行化那么吸引人,所以它们没有受到人们的重视。我们应该改变这一点。

我很乐意请任何帮助使存储格式成为一个更吸引人的话题的人喝啤酒。

调度

单机

单机动态任务调度器非常非常可靠。它大约有两个目标

  1. 使用机器的所有核心
  2. 选择允许释放中间结果的任务

这使得我们能够在有限的空间内快速执行复杂的工作流程。这个调度器是 dask 内所有执行的基础。我非常满意。我想找到方法将其更广泛地暴露给其他库。非常欢迎在此提出建议。

我们仍然会遇到它表现不佳的情况(参见 issue 874),但到目前为止,每当出现这些情况时,我们都能够增强调度器。

分布式集群

在过去的几个月里,我们一直在开发另一个用于分布式内存计算的调度器。它应该是对现有 dask 集合扩展到“大数据”系统的一个很好的补充。它是实验性的,但现在已经可用,文档可在以下链接中找到

欢迎提供反馈意见。如果您喜欢干净可靠的软件,我建议您再等一两个月。它将会改名,使用一个不那么通用的名称。


博客评论由 Disqus 提供支持