最佳实践

开始使用 Dask 数组很容易,但要*熟练*使用它们确实需要一些经验。本页包含最佳实践的建议,并包括常见问题的解决方案。

使用 NumPy

如果你的数据可以轻松地放入内存,并且你不受性能限制,那么使用 NumPy 可能是一个正确的选择。Dask 增加了另一层复杂性,这可能会成为障碍。

如果你只是寻找速度提升而不是可扩展性,那么你可能需要考虑像 Numba 这样的项目。

选择一个合适的块大小

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

虽然最佳的大小和形状高度依赖于具体问题,但很少见到低于100 MB的块大小。如果你处理的是float64数据,那么对于一个二维数组来说,这大约是``(4000, 4000)``的大小,而对于一个三维数组来说,这大约是``(100, 400, 400)``的大小。

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

调整你的块

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

例如,如果我们有一个HDF文件,其块大小为 (128, 64),我们可能会选择一个块形状为 (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 数组将查找 .chunks 属性并使用它来提供良好的分块。

避免过度订阅线程

小技巧

在使用 distributed 调度器时,当使用 保姆 工作线程时,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. 在 Dask 数组和 NumPy 之间切换,使用一致的 API

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数组。