我正在尝试读取一个大的(不会容纳在内存中)镶木地板数据集,然后从中取样。数据集的每个分区都完全适合内存。
数据集大约有20Gb磁盘数据,分为104个分区,每个分区约200Mb。我不想在任何时候使用超过40Gb的内存,因此我分别设置了n_workers
和memory_limit
。
我的假设是,Dask将加载尽可能多的分区,从中采样,从内存中废弃它们,然后继续加载下一个分区。或类似的东西。
相反,从执行图(并行执行104个加载操作,每个示例之后)来看,它似乎试图同时加载所有分区,因此工作人员由于内存不足而被杀死。
我想念什么吗?
这是我的代码:
from datetime import datetime
from dask.distributed import Client
client = Client(n_workers=4, memory_limit=10e9) #Gb per worker
import dask.dataframe as dd
df = dd.read_parquet('/path/to/dataset/')
df = df.sample(frac=0.01)
df = df.compute()
要重现该错误,您可以使用此代码创建一个模拟数据集,其大小是我尝试加载的模拟数据集的1/10,然后尝试使用1GB memory_limit=1e9
进行补偿的代码。
from dask.distributed import Client
client = Client() #add restrictions depending on your system here
from dask import datasets
df = datasets.timeseries(end='2002-12-31')
df = df.repartition(npartitions=104)
df.to_parquet('./mock_dataset')
答案 0 :(得分:0)
Parquet是一种有效的二进制格式,具有编码和压缩功能。内存中很有可能比您想象的要占用更多的空间。
为了对数据进行1%的采样,每个分区都被加载并整体扩展到内存中,然后再进行子选择。这带来了缓冲区副本的大量内存开销。每个工作线程将需要容纳当前处理的块以及迄今为止在该工作线程上累积的结果,然后任务将复制所有这些内容以进行最终的concat操作(这也涉及复制和开销)。
通常的建议是,每个工作人员应“多次”访问每个分区的内存大小,在您的情况下,磁盘上的磁盘大小约为2GB,内存更大。