选自pythonspeed
作者:Itamar Turner-Trauring
机器之心编译
参与:高璇、杜伟
在编写软件的过程中,开发人员需要处理大量的数据,因而常常会遇到内存不足的情况。虽然我们都知道,解决内存不足的简单粗暴方法就是往里砸钱,但有时自己的经济实力不允许这么任性。本文作者提出了三种技巧:数据压缩、分块和索引,以此从软件本身解决了内存不足的窘境。
在你编写用于处理数据的软件时,当只用一个小的示例文件做测试,软件就可以很好地运行。
但是,当加载实际数据时,程序立刻崩溃。
原因是没有足够的内存——如果你只有 16GB 的 RAM,则无法加载 100GB 的文件。
有时操作系统耗尽内存,导致内存无法分配,程序就只能崩溃。
所以,你可以做什么?
要启动一个大数据集,需要做的是:
这样做简直让人心力交瘁;
幸运的是,在许多情况下,你也不必这么做。
你只需一种简单易用的解决方案:
在一台计算机上用最少的设置即可处理数据,并且尽可能使用你已经在用的库。
而且在很多时候,你可以使用一种被称为「核外计算」的技术来实现。
文章接下来将展示如何将这些技术应用于 NumPy 和 Pandas 等特定库。
在继续讨论解决方案之前,让我们先阐明问题出现的原因。
你可以使用计算机的内存(RAM)读取和写入数据,但是硬盘驱动器也可以读取和写入数据——那么为什么计算机需要 RAM 呢?
而且磁盘比 RAM 便宜,它通常可以包含所有数据,那么为什么代码不能改为仅从磁盘读取和写入数据呢?
从理论上讲,这是可行的。
但即使是更新、更快的固态硬盘(SSD)也比 RAM 慢得多:
从 SSD 读取:约 16,000 纳秒
从 RAM 读取:约 100 纳秒
如果想要快速计算,数据必须匹配 RAM,否则代码运行速度可能会慢 150 倍。
解决内存不足的最简单粗暴的方法就是
往里砸钱
。
你可以买台计算机或者租用云虚拟机(VM),后者的内存比大多数笔记本电脑都要多。
以 2019 年 11 月市场价为例,你可以:
这些只是我简单搜索得到的价格,如果进行一些深入研究,则可能需要更全的价格和产品。
如果花钱就能解决你的内存问题,那通常是最便宜的解决方案
:
毕竟时间就是金钱。
但是,有时花钱也解决不了问题。
例如,如果你要处理许多数据任务,在一段时间内,云计算可能是很顺手的解决方案,但却也是昂贵的解决方案。
在一项研究工作中,我所使用软件的计算成本将耗尽该产品的所有预计收入,包括我的薪水在内,这样代价就太大了。
如果购买/租用更多的 RAM 是不够或不现实的,下一步就是弄清楚如何通过更改软件来减少内存使用。
数据压缩意味着使用更少的内存来表示数据。
压缩有两种形式:
请注意,我说的不是 ZIP 或 gzip 文件,因为这些文件通常涉及磁盘压缩。
要处理 ZIP 文件中的数据,首先需要解压缩到 RAM 中。
因此,这无济于事。
例如,假设你的数据有两个值,并且将永远只有这两个值:
"AVAILABLE"和"UNAVAILABLE"。
你可以将它们存储为布尔值,True 或 False,这样可以将其存储为 1 个字节,而不是每个条目都要占用 10 个甚至更多字节。
你甚至可以将表示降低到表示布尔值所需的单个位,从而将内存使用量减少到原来的八分之一。
当你需要处理所有数据但不需要一次将所有数据加载到内存中时,分块很有用。
你可以将数据分块加载到内存中,一次只处理一个数据块(或者按照后文提到的,并行处理多个块)。
例如,假设你要查找一本书中最长的单词。
你可以一次将所有数据加载到内存中:
largest_word = ""
for word in book.get_text().split():
if len(word) > len(largest_word):
largest_word = word
即使假设在我们的情况下,书不适配内存,可以将其改为一页一页的加载。
largest_word = ""
for page in book.iterpages():
for word in page.get_text().split():
if len(word) > len(largest_word):
largest_word = word
你需要使用的内存要少得多,因为在任何给定的时间内只有一页书在内存中只有一页书在内存中。
最后,你还是会得到相同的答案。
当你只需要使用数据的一个子集,并且希望在不同的时间加载数据的不同子集时,索引很有用。
你可以通过分块解决这种情况:
每次加载所有数据,然后过滤掉不需要的数据。
但这很慢,因为需要加载许多不相关的数据。
如果只需要部分数据,则最好使用索引,而不是分块,索引最好使用数据摘要,它可以告诉你在哪里找到所需的数据。
想象一下,您只想阅读本书中有关土豚(ardarvarks)的部分。
如果使用分块,则需要逐页阅读整本书,以查找 ardarvarks,但这将花费相当长的时间。
或者,你可以利用书的索引,找到「Aardvarks」的条目。
它可能会告诉你阅读第 7、19 和 120-123 页。
现在你就可以阅读这些页面,并且仅阅读这些页面,这要快得多。
这样之所以可行,是因为索引比整本书要小得多,因此将索引加载到内存中以查找相关数据要容易得多。
mydata/
2019-Jan.csv
2019-Feb.csv
2019-Mar.csv
2019-Apr.csv
...
如果要获取 2019 年 3 月的数据,则只需加载 2019-Mar.csv 即可,而无需加载 2 月、7 月或任何其他月份的数据。
解决 RAM 不足的最简单方法是花钱获得更多 RAM。
但是,如果这行不通或者不现实时,就可以使用压缩、分块或索引等技巧。
这些技巧可以应用在许多不同的软件包和工具中。
即使大数据系统也基于这些技巧构建:
例如,使用多台计算机来处理数据块。
原文链接:
https://pythonspeed.com/articles/data-doesnt-fit-in-memory/
「WAIC 开发者·临港人工智能开发者大会」将于 2019 年 12 月 6 日-7 日在上海临港举办。本次大会设有主题演讲、开发者工作坊、开发者挑战赛、技术和产业闭门研讨会等环节。邀请全球AI开发者在现场:听前沿理论+学实战干货+动手挑战赛。点击阅读原文,立即报名。