对于大于内存大小=(M,N)的dask数组:如何将chunks=(1,N)中的chunks重新划分为chunks=(M,1)?

对于大于内存大小=(M,N)的dask数组:如何将chunks=(1,N)中的chunks重新划分为chunks=(M,1)?,dask,dask-distributed,Dask,Dask Distributed,例如,为了沿着整个轴应用以Numpy/Numba编码的IIR滤波器,我需要将asize=(M,N)dask数组从chunks=(m0,n0)重新分块到chunks=(m1,N)和m1

例如,为了沿着整个轴应用以Numpy/Numba编码的IIR滤波器,我需要将a
size=(M,N)
dask数组从
chunks=(m0,n0)
重新分块到
chunks=(m1,N)
m1

由于Dask避免重复任务,因此在rechunk拆分/rechunk合并期间,它将在内存中具有值
(m0,N)
(x2?)的数据。有没有办法优化图形以避免这种行为

我知道在哪里可以找到手工优化Dask图的信息。但是有没有一种方法可以调整调度策略以允许重复任务,或者(自动)重新安排图表以最小化重新调整期间的内存使用

下面是一个最小的示例(对于
chunks=(M,1)
→ <代码>块=(1,N)
):

从dask导入数组作为da
从dask.distributed导入客户端
#将内存限制为4 GB
客户机=客户机(内存限制=4e9)
#使用chunks=(M,1)创建80 GB随机数组
arr=da.random.uniform(-1,1,size=(1e5,1e5),chunks=(1e5,1))
#计算平均值(这很有效!)
arr.mean().compute()
#重块到块=(1,N)
arr=arr.rechunk((1,1e5))
#计算平均值(这将达到内存限制!)
arr.mean().compute()

不幸的是,您处于最坏的情况下,您需要计算每个输入块,然后才能获得单个输出块

Dask的重块操作很不错,它们会在过渡期间将内容重块到中等大小的块中,因此这可能在内存不足的情况下工作,但您肯定会将内容写入磁盘


简而言之,原则上你不应该做额外的事情。从理论上讲,Dask的重装算法应该能够处理这个问题。如果您愿意,您可以使用
阈值=
块大小限制=
关键字进行重新搜索。

关键字
块大小限制=
导致某种解决方案

(下面,我使用了一个更小的阵列,因为我没有剩余的80GB磁盘可供溢出。)

从dask导入数组作为da
从dask.distributed导入客户端
#将内存限制为1 GB
客户端=客户端(n个工作线程=1,每个工作线程的线程数=1,内存限制=1e9)
#创建3.2 GB阵列
arr=da.random.uniform(-1,1,size=(2e4,2e4),chunks=(2e4,1e1))
#检查图形大小
打印(len(arr.uu dask_graph_uu()),“图中的节点”)#2000个节点
#计算
打印(arr.mean().compute())#需要11.9秒。不会溢出来。
#重新创建阵列,并使用块大小限制=1e3重新填充
arr=da.random.uniform(-1,1,size=(2e4,2e4),chunks=(2e4,1e1))
arr=arr.rechunk((2e1,2e4),块大小限制=1e3)
#检查图形大小
打印(len(arr.uu dask_graph_uuu()),“图中的节点”)#32539个节点
#计算
打印(arr.mean().compute())#需要140秒,将~5GB的内存溢出到磁盘。
#重新创建阵列并使用默认KWARG重新对齐
arr=da.random.uniform(-1,1,size=(2e4,2e4),chunks=(2e4,1e1))
arr=arr.rechunk((2e1,2e4))
#检查图形大小
打印(len(arr.uu dask_graph_uuu()),“图中的节点”)#9206个节点
#计算
打印(arr.mean().compute())#工作进程在95%的内存使用率下死亡

有没有办法允许重复执行任务?据我所知,达斯克将努力不重复任何事情。比如说,对于每个输出块,计算所有输入块,保留当前块所需的内容,丢弃所有不需要的内容。(我想到的情况是,我只有内存和CPU。)不幸的是,今天没有