我试图在Dask中找到相应的Spark unpersist
。我的需要
对于明确的独立主义者,出现在以下情况:
df
,例如,因为它需要
计算许多聚合以进行预处理。基本示例如下:
def iterative_algorithm(df, num_iterations):
for iteration in range(num_iterations):
# Transformation logic requiring e.g. map_partitions
def mapper(df):
# ...
return df
df = df.map_partitions(mapper)
df = df.persist()
# Now I would like to explicitly unpersist the old snapshot
return df
在Spark中,可以通过释放旧快照来解决问题
明确。显然Dask没有明确的unpersist
但是处理问题
通过参考计算标的期货。这意味着这个例子
上面会复制数据,因为调用上下文包含引用
旧的期货,而子功能持有对修改的引用
坚持。在我的实际用例中,有几个这样的嵌套级别
转换调用,导致数据甚至多次复制。
有没有办法在没有任何额外副本的情况下解决迭代缓存?
答案 0 :(得分:2)
我会发布一些想法如何解决这个问题,但我仍然在寻找更好的方法 的替代品。
由于引用计数,避免副本是很棘手的,但那里
是可能性。问题是调用者持有引用的结果
原始df
以及通过df = df.<method>
创建新实例的子功能
调用。要解决这个问题,我们必须自己引用df
可变的。不幸的是,Python一般不允许改变引用
函数参数。
解决方案1:天真可变参考
解决该限制的最简单方法是将df
包装到列表中
或者说。在这种情况下,子功能可以修改外部参考,例如,由:
df_list[0] = df_list[0].map_partitions(mapper)
df_list[0] = df_list[0].persist()
然而,这在语法上很尴尬,因此必须非常小心
通过df = df_list[0]
简化语法再次创建新的引用
潜在的期货,可能导致数据重复。
解决方案2:基于包装器的可变引用
改进之后,可以编写一个包含引用的小包装类 到数据帧。通过这个包装器,子函数可以变异 参考资料。要改进语法问题,可以考虑使用包装器 应该自动将功能委托给数据框或继承 从中。总的来说,这个解决方案也感觉不对。
解决方案3:明确的突变
为了避免其他解决方案的语法问题,我目前更喜欢以下内容
变体,有效模拟map_partitions
的可变版本
和persist
通过原始df
实例的原位修改。
def modify_inplace(old_df, new_df):
# Currently requires accessing private fields of a DataFrame, but
# maybe this could be officially supported by Dask.
old_df.dask = new_df.dask
old_df._meta = new_df._meta
old_df._name = new_df._name
old_df.divisions = new_df.divisions
def iterative_algorithm(df, num_iterations):
for iteration in range(num_iterations):
def mapper(df):
# Actual transform logic...
return df
# Simulate mutable/in-place map_partitions
new_df = df.map_partitions(mapper)
modify_inplace(df, new_df)
# Simulate mutable/in-place persist
new_df = df.persist()
modify_inplace(df, new_df)
# Technically no need to return, because all operations were in-place
return df
这对我来说相当不错,但需要仔细遵循这些规则:
df = df.<method>
之类的所有不可变调用。df
的引用。例如,在调用persist之前,为了语法上的方便使用some_col = df["some_sol"]
这样的变量需要del some_col
。否则,使用some_col
存储的引用将再次导致数据重复。答案 1 :(得分:2)
您可以按如下方式编写发布函数:
from distributed.client import futures_of
def release(collection):
for future in futures_of(collection):
future.release()
这只会释放当前实例。如果您有多个这些期货的实例,您可能需要多次调用它或添加如下所示的循环:
while future.client.refcount[future.key] > 0:
但是,如果你有其他副本有理由浮动,通常多次调用这一点似乎是不明智的。