例如,为了沿整个轴应用以Numpy / Numba编码的IIR过滤器,我需要将size=(M, N)
快数组从chunks=(m0, n0)
换成{{1} }和chunks=(m1, N)
。
由于Dask避免重复执行任务,因此在rechunk-split / rechunk-merge期间,它将在内存中存储值得m1 < m0
(x 2?)的数据。有没有一种优化图的方法来避免这种行为?
我知道从哪里可以找到有关优化Dask图的信息。但是,有没有一种方法可以调整调度策略以允许重复执行任务,或者(自动)重新安排图形以最大程度地减少重新绑定期间的内存使用?
这是一个最小的示例(对于(m0, N)
→chunks=(M, 1)
的极端情况):
chunks=(1, N)
答案 0 :(得分:2)
不幸的是,您处在最坏的情况下,您需要计算每个输入块,然后才能获得单个输出块。
Dask的重分块操作相当不错,并且在过渡期间它们会将它们重新分组为中等大小的块,因此这可能会在内存不足的情况下起作用,但是您肯定会把事情写到磁盘上。
简而言之,原则上您不需要做任何额外的事情。理论上,Dask的重分配算法应该可以解决这个问题。如果您愿意,可以使用threshold=
和block_size_limit=
关键字重新组合。
答案 1 :(得分:0)
通过block_size_limit=
关键字可以找到一种解决方案。
(下面,我使用一个较小的阵列,因为我没有80GB的磁盘可溢出。)
from dask import array as da
from dask.distributed import Client
# limit memory to 1 GB
client = Client(n_workers=1, threads_per_worker=1, memory_limit=1e9)
# Create 3.2 GB array
arr = da.random.uniform(-1, 1, size=(2e4, 2e4), chunks=(2e4, 1e1))
# Check graph size
print(len(arr.__dask_graph__()), "nodes in graph") # 2000 nodes
# Compute
print(arr.mean().compute()) # Takes 11.9 seconds. Doesn't spill.
# re-create array and rechunk with block_size_limit=1e3
arr = da.random.uniform(-1, 1, size=(2e4, 2e4), chunks=(2e4, 1e1))
arr = arr.rechunk((2e1, 2e4), block_size_limit=1e3)
# Check graph size
print(len(arr.__dask_graph__()), "nodes in graph") # 32539 nodes
# Compute
print(arr.mean().compute()) # Takes 140 seconds, spills ~5GB to disk.
# re-create array and rechunk with default kwargs
arr = da.random.uniform(-1, 1, size=(2e4, 2e4), chunks=(2e4, 1e1))
arr = arr.rechunk((2e1, 2e4))
# Check graph size
print(len(arr.__dask_graph__()), "nodes in graph") # 9206 nodes
# Compute
print(arr.mean().compute()) # Worker dies at 95% memory use