使用 Dask 数组很容易上手,但使用好它们确实需要一些经验。此页面包含最佳实践建议,并包含常见问题的解决方案。
如果您的数据在 RAM 中很合适,并且您不受性能限制,那么使用 NumPy 可能是正确的选择。Dask 增加了另一层复杂性,这可能会妨碍您。
如果您只是在寻找加速而不是可扩展性,那么您可能需要考虑像Numba这样的项目
Dask Array 用户的一个常见性能问题是他们选择的 块大小要么太小(导致大量开销),要么与他们的数据对齐不佳(导致读取效率低下)。
虽然最佳大小和形状是高度特定于问题的,但很少看到 小于 100 MB 的块大小。如果您正在处理 float64 数据,那么这大约是 2D 数组或 3D 数组的大小。(4000, 4000)(100, 400, 400)
您想选择一个大的块大小以减少 Dask 必须考虑的块数量(这会影响开销),但也要足够小,以便它们中的许多块可以同时放入内存中。Dask 在内存中的块数通常是活动线程数的两倍。
读取数据时,您应该将您的chunk与您的存储格式对齐。大多数数组存储格式本身将数据存储在块中。如果您的 Dask 数组块不是这些块形状的倍数,那么您将不得不重复读取相同的数据,这可能会很昂贵。请注意,尽管通常存储格式选择的块大小比 Dask 的理想大小要小得多,比 100MB 更接近 1MB。在这些情况下,您应该选择与存储块大小一致的 Dask 块大小,并且每个 Dask 块维度都是存储块维度的倍数。
因此,例如,如果我们有一个大小为 s 的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))
请注意,如果您提供,则 Dask Array 将寻找一个 属性并使用它来提供一个好的分块。chunks=‘auto’.chunks
默认情况下,Dask 将运行与逻辑核心一样多的并发任务。它假设每个任务将消耗大约一个核心。但是,许多数组计算库本身是多线程的,这可能会导致争用和低性能。特别是支持 NumPy 的大多数线性代数例程的 BLAS/LAPACK 库通常是多线程的,并且需要被告知只使用一个线程。您可以使用以下环境变量来执行此操作(使用export下面的 bash 命令,但这可能因您的操作系统而异)。
export OMP_NUM_THREADS=1
export MKL_NUM_THREADS=1
export OPENBLAS_NUM_THREADS=1
您需要在启动 Python 进程之前运行它以使其生效。
Xarray包围绕Dask Array,因此提供了相同的可扩展性,但在处理复杂数据集时也增加了便利性。特别是 Xarray 可以帮助解决以下问题:
将多个数组作为一致的数据集一起管理
一次从一堆 HDF 或 NetCDF 文件中读取
使用一致的 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[, 深度, 边界, ...])
在有一些重叠的数组块上映射一个函数
reduction(x, 块,聚合[,轴,...])
通用版的减法
这些函数可以帮助你将你为 NumPy 函数编写的函数应用到更大的 Dask 数组上。