最佳实践

Dask 数组入门很容易,但要用好它们需要一些经验。本页包含最佳实践建议,并提供了常见问题的解决方案。

使用 NumPy

如果您的数据能轻松放入 RAM 且性能不是瓶颈,那么使用 NumPy 可能是正确的选择。Dask 会增加另一层复杂性,这可能会带来麻烦。

如果您只是寻求加速而非可伸缩性,那么可以考虑像 Numba 这样的项目。

选择合适的块大小

Dask Array 用户遇到的一个常见性能问题是他们选择了过小的块大小(导致大量开销)或与数据对齐不佳的块大小(导致读取效率低下)。

虽然最优的尺寸和形状高度依赖于具体问题,但块大小低于 100 MB 的情况很少见。如果您处理的是 float64 数据,那么对于一个 2D 数组,这个大小大约是 (4000, 4000);对于一个 3D 数组,大约是 (100, 400, 400)

您希望选择一个足够大的块大小来减少 Dask 需要考虑的块数量(这会影响开销),但也要足够小,以便许多块可以同时放入内存。Dask 通常会在内存中保留两倍于活动线程数的块。

调整块方向

读取数据时,应使块与存储格式对齐。大多数数组存储格式本身就以块的形式存储数据。如果您的 Dask 数组块不是这些存储块形状的倍数,那么您将不得不重复读取相同的数据,这可能会非常耗时。但请注意,存储格式选择的块大小通常比 Dask 理想的大小要小得多,更接近 1MB 而不是 100MB。在这种情况下,您应该选择一个与存储块大小对齐且每个 Dask 块维度都是存储块维度的倍数的 Dask 块大小。

例如,如果我们有一个块大小为 (128, 64) 的 HDF 文件,我们可能会选择 (1280, 6400) 的块形状。

>>> import h5py
>>> storage = h5py.File('myfile.hdf5')['x']
>>> storage.chunks
(128, 64)

>>> import dask.array as da
>>> x = da.from_array(storage, chunks=(1280, 6400))

请注意,如果您提供 chunks='auto',Dask Array 将查找 .chunks 属性,并使用它来提供良好的分块。

避免过度订阅线程

提示

使用 distributed 调度器时,在使用 Nanny 工作节点时,OMP_NUM_THREADSMKL_NUM_THREADSOPENBLAS_NUM_THREADS 环境变量会自动设置为 1。这有助于在常见情况下避免过度订阅线程。

默认情况下,Dask 将运行与逻辑核心数量相同的并发任务。它假定每个任务大约消耗一个核心。然而,许多数组计算库本身就是多线程的,这可能会导致竞争和低性能。特别是支持大多数 NumPy 线性代数例程的 BLAS/LAPACK 库通常是多线程的,需要明确告知它们只使用一个线程。您可以使用以下环境变量来实现这一点(下面使用 bash export 命令,但这可能会因您的操作系统而异)。

export OMP_NUM_THREADS=1
export MKL_NUM_THREADS=1
export OPENBLAS_NUM_THREADS=1

您需要在启动 Python 进程之前运行此命令,使其生效。

考虑使用 Xarray

软件包 Xarray 封装了 Dask Array,因此提供了相同的可伸缩性,同时在处理复杂数据集时也增加了便利性。特别是 Xarray 可以在以下方面提供帮助:

  1. 将多个数组作为一个一致的数据集进行管理

  2. 一次性读取一组 HDF 或 NetCDF 文件

  3. 使用一致的 API 在 Dask Array 和 NumPy 之间切换

Xarray 被广泛应用于各种领域,包括物理学、天文学、地球科学、显微镜学、生物信息学、工程学、金融学和深度学习。Xarray 还有一个活跃的用户社区,善于提供支持。

构建自己的操作

通常我们希望执行 Dask Array 中没有完全对应函数的计算。在这种情况下,我们可以使用一些更通用的函数来构建自己的操作。这些函数包括:

blockwise(func, out_ind, *args[, name, ...])

张量操作:广义内积和外积

map_blocks(func, *args[, name, token, ...])

将函数映射到 dask 数组的所有块上。

map_overlap(func, *args[, depth, boundary, ...])

将函数映射到具有重叠区域的数组块上

reduction(x, chunk, aggregate[, axis, ...])

通用的归约操作

这些函数可以帮助您将为 NumPy 函数编写的函数应用于更大的 Dask 数组。