如何在Dask中实现无数据重复的增量缓存?
我试图在Dask中找到Spark的如何在Dask中实现无数据重复的增量缓存?,dask,Dask,我试图在Dask中找到Spark的unpersist的等价物。我的需要 对于显式非持久性,出现在以下情况: 调用上下文已经保留了一个大的df,例如,因为它需要 为预处理目的计算多个聚合 调用上下文调用一个函数,该函数也需要调用persist,例如。, 因为它执行一些迭代算法 一个基本示例如下所示: def迭代算法(df,num迭代): 对于范围内的迭代(num_迭代): #需要映射分区等转换逻辑 def映射器(df): # ... 返回df df=df.map\u分区(映射器) df=df.
unpersist
的等价物。我的需要
对于显式非持久性,出现在以下情况:
- 调用上下文已经保留了一个大的
,例如,因为它需要 为预处理目的计算多个聚合df
- 调用上下文调用一个函数,该函数也需要调用persist,例如。, 因为它执行一些迭代算法
def迭代算法(df,num迭代):
对于范围内的迭代(num_迭代):
#需要映射分区等转换逻辑
def映射器(df):
# ...
返回df
df=df.map\u分区(映射器)
df=df.persist()
#现在我想显式地取消旧快照的持久性
返回df
在Spark中,可以通过释放旧快照来解决此问题
明确地显然,Dask没有显式的unpersist
,但可以处理这个问题
通过基础期货的参考计数。这意味着示例
因为调用上下文包含引用,所以上面的操作将复制数据
对于旧的期货,而子函数保存对已修改期货的引用
坚持在我的实际用例中,有几个嵌套的级别
转换调用,导致数据重复甚至多次
有没有一种方法可以在不增加任何副本的情况下解决迭代缓存问题?我将发布一些解决方法,但我仍在寻找更好的方法
替代品
由于引用计数的原因,避免复制是很困难的,但是
这些都是可能的。问题是调用方持有引用的结果
到原始的df
和通过df=df创建新实例的子函数。
电话。为了解决这个问题,我们必须引用df
本身
易变的。不幸的是,Python通常不允许对引用进行变异
函数参数的定义
解决方案1:原始可变引用
解决该限制的最简单方法是将df
包装到一个列表中
或说明。在这种情况下,子功能可以修改外部参考,例如:
df_列表[0]=df_列表[0]。映射分区(映射器)
df_list[0]=df_list[0]。persist()
然而,这在句法上很尴尬,必须非常小心,因为
通过df=df_list[0]
简化语法,再次创建对
潜在的未来,这可能会导致数据重复
解决方案2:基于包装器的可变引用
在此基础上,可以编写一个小的包装器类,其中包含一个引用
到数据帧。通过这个包装器,子函数可以发生变化
参考资料。为了改进语法问题,可以考虑包装器。
应自动或继承将功能委托给数据帧
从它。总的来说,这个解决方案也感觉不对劲
解决方案3:显式突变
为了避免其他解决方案的语法问题,我目前更喜欢以下解决方案
变量,它有效地模拟了map\u分区的可变版本
并通过对原始df
实例的就地修改来保持
def就地修改(旧的、新的):
#当前需要访问数据帧的私有字段,但
#也许这可以得到Dask的官方支持。
旧的_df.dask=新的_df.dask
旧的_-df._-meta=新的_-df._-meta
旧的_-df._-name=新的_-df._-name
旧分区=新分区
def迭代算法(df、num迭代):
对于范围内的迭代(num_迭代):
def映射器(df):
#实际转换逻辑。。。
返回df
#模拟可变/就地映射分区
new_df=df.map_分区(映射器)
就地修改(df,新的_df)
#模拟可变/就地持久化
new_df=df.persist()
就地修改(df,新的_df)
#从技术上讲,无需返回,因为所有操作都已就绪
返回df
这对我来说相当有效,但需要仔细遵守以下规则:
- 用上面的模式替换所有不可变的调用,如
df=df.
- 注意创建对
的引用。例如,为了语法上的方便,使用像df
这样的变量需要在调用persist之前some\u col=df[“some\u sol”]
。否则,存储在某些列中的引用将再次导致数据重复del some\u col
from distributed.client import futures_of
def release(collection):
for future in futures_of(collection):
future.release()
这将只释放当前实例。如果您有多个这些未来的实例,您可能需要多次调用它或添加如下循环:
while future.client.refcount[future.key] > 0:
但是,通常多次调用此函数似乎是不明智的,因为您可能会有其他副本在您的
modify\u in place
函数中包含df.divisions