本节书摘来自华章社区《Clojure数据分析秘笈》一书中的第2章,第2.8节大数据集的延迟处理,作者(美)Eric Rochester,更多章节内容可以访问云栖社区“华章社区”公众号查看
2.8 大数据集的延迟处理
Clojure的一个卓越特性是它的大多数序列处理函数都是延迟处理的。这使得可以非常省力地处理大数据集。然而,当与从文件或其他输入设备读入的过程结合时,有很多需要注意的地方。
在本方法中,将介绍安全延迟读入CSV文件的几种方式。clojure.data.csv/read-csv默认就是延迟的,如何在正确时间关闭文件的同时保持这一特性呢?
2.8.1 准备工作
需要加载将在REPL中使用的库。使用以下命令完成:
![423fde8b85ee5447f2ac0a61b9ece09e28ae171e](https://yqfile.alicdn.com/423fde8b85ee5447f2ac0a61b9ece09e28ae171e.png?x-oss-process=image/resize,w_1400/format,webp)
可以发现,当函数返回延迟序列时,还没有读入任何数据。但是当使用with-open形式退出时,文件自动关闭,发生了什么?
首先,文件被打开并传给read-csv函数,返回一个延迟序列。这个延迟序列被关闭文件的函数with-open返回。最后,REPL尝试将延迟序列输出到屏幕上。read-csv函数尝试从文件中读出数据。但在此时,文件已经关闭,因此抛出IOException。
这是编写函数时一个非常常见的问题。这个问题在我每次从数据库读数据时都会由于某些原因而出现。
- 为了修正这个问题,强制读入文件所有行:
![0a93f292dee839082b4c35e6bab6d4784838056d](https://yqfile.alicdn.com/0a93f292dee839082b4c35e6bab6d4784838056d.png?x-oss-process=image/resize,w_1400/format,webp)
这个版本没问题。
2.8.3 实现原理
lazy-read-csv函数的最新版本起效是由于它读入csv/read-csv产生的延迟序列并将其装入另一个序列,当不再从CSV文件中读入时这个序列关闭输入文件。这个过程比较复杂是因为处理了两次层次的输入:读入文件和读入CSV。当上层的输入(读入CSV)完成时,将触发底层(读入文件)的操作。
然而,有了这个函数,又一次得到了一个简单好用的接口,将它提供给调用者并将其复杂的部分隐藏起来。
遗憾的是,这仍然有一个严重的问题:如果不打算读入整个文件,文件句柄不会关闭。在一些仅读入文件一部分的场景中,lazy-read-ok函数可能是最好的。