输入为吉字节/泰字节时有什么变化?
今天我迈出了第一步,开始接触真正的科学计算。我看到一个数据集,最小的文件有48000个字段和1600行(这是关于几个人的基因组数据,针对的是22号染色体)。而这个数据集在大数据的世界里被认为是小的。
我会写Python,所以我花了几个小时在研究HDF5、Numpy和PyTable,但我还是觉得自己对一个有着一TB(千兆字节)大小的数据集到底意味着什么还没有完全理解。
比如,有人提到,对于更大的数据集,想把整个数据读入内存几乎是不可能的,这不是因为机器的内存不够,而是因为系统的地址空间不够!这让我大吃一惊。
在课堂上我依赖的哪些假设在面对这么大的输入时根本行不通?我需要开始做些什么,或者以不同的方式思考哪些问题?(这不一定要和Python有关。)
4 个回答
有些编程语言在处理数据时占用的内存比较少,但对于这么大规模的数据来说,这一点并不重要。无论你用什么语言,你都不可能把所有的数据都放在内存里,所以Python的“开销”在这里并没有太大关系。正如你提到的,实际上没有足够的地址空间来引用所有这些数据,更别提把它们都存起来了。
这通常意味着你要么把数据存到数据库里,要么增加一些计算机资源,这样可以扩展你的地址空间和内存。实际上,你可能会同时做这两件事。使用数据库时,有一点很重要:数据库不仅仅是你不使用数据时的存放地方,你还可以在数据库里进行操作,而且应该尽量这样做。你选择的数据库技术会对你能做的工作产生很大影响,比如SQL数据库就非常适合进行大量的集合运算,并且效率很高(当然,这也意味着数据库的结构设计在整体架构中非常重要)。不要只是把数据提取出来在内存中处理,尽量利用数据库的计算查询能力,在把数据放到内存之前尽可能多地进行处理。
简单来说,我认为主要的区别有:
- 你应该提前知道可能的瓶颈在哪里(是输入输出还是CPU),然后专注于找到最合适的算法和基础设施来解决这个问题。输入输出通常是瓶颈。
- 选择和调整算法往往比其他选择更重要。
- 即使是微小的算法和访问模式的变化,也可能对性能产生巨大的影响。你会进行很多微优化。所谓的“最佳”解决方案通常依赖于具体的系统。
- 和同事以及其他科学家交流,借鉴他们在这些数据集上的经验。很多技巧在教科书里是找不到的。
- 预先计算和存储数据可以非常有效。
带宽和输入输出
最开始,带宽和输入输出通常是瓶颈。给你一个参考:在理论上,使用SATA 3时,读取1TB的数据大约需要30分钟。如果你需要随机访问、重复读取或写入,通常最好在内存中进行,或者需要更快的东西(比如iSCSI和InfiniBand)。理想情况下,你的系统应该能够进行并行输入输出,以尽可能接近你所使用接口的理论极限。例如,在不同进程中并行访问不同文件,或者在HDF5上使用MPI-2 I/O是相当常见的。理想情况下,你还应该并行进行计算和输入输出,这样其中一个就可以“免费”进行。
集群
根据你的情况,输入输出或CPU可能成为瓶颈。无论是哪一个,如果你能有效地分配任务,使用集群可以实现巨大的性能提升(例如MapReduce)。这可能需要完全不同于典型教科书例子的算法。在这里花时间开发,往往是最值得的。
算法
在选择算法时,算法的“大O”表示法非常重要,但相似“大O”的算法在性能上可能有很大差异,具体取决于局部性。算法的局部性越差(即缓存未命中和主内存未命中越多),性能就越差——访问存储通常比访问主内存慢一个数量级。经典的改进例子包括分块矩阵乘法或循环交换。
计算机、语言、专用工具
如果你的瓶颈是输入输出,这意味着大数据集的算法可以通过增加主内存(例如64位)或使用内存消耗更少的编程语言/数据结构(例如在Python中,__slots__
可能会有帮助)来受益,因为更多的内存可能意味着每个CPU时间的输入输出更少。顺便提一下,拥有TB级主内存的系统并不少见(例如HP Superdomes)。
同样,如果你的瓶颈是CPU,使用更快的机器、语言和编译器,能够让你利用架构的特殊功能(例如SIMD,如SSE)可能会将性能提高一个数量级。
你查找和访问数据的方式,以及存储元信息的方式,对性能也非常重要。你通常会使用平面文件或特定领域的非标准包来存储数据(例如,不直接使用关系数据库),这样可以更高效地访问数据。例如,kdb+是一个专门用于大时间序列的数据库,而ROOT使用TTree
对象来高效访问数据。你提到的pyTables也是一个例子。
我现在在石油行业的一个小角落从事高性能计算,常常处理你们关心的那种规模的数据集。这里有几点可以考虑的内容:
在这个领域,数据库并不太受欢迎。我们几乎所有的数据都保存在文件中,有些文件甚至是70年代设计的磁带文件格式。我觉得不使用数据库的部分原因是历史原因;在10年前,甚至5年前,我认为Oracle等数据库根本无法处理单个TB级别的数据集,更不用说管理成千上万个这样的数据集了。
另一个原因是,数据库分析和设计的规范化规则与科学数据集的性质之间存在概念上的不匹配。
我认为(虽然不太确定)现在性能方面的原因已经不那么有说服力了。而且,随着大多数主要数据库能够处理空间数据集,这种概念不匹配的问题可能也不那么紧迫了,因为空间数据集通常与其他科学数据集的概念更接近。我看到越来越多的数据库被用来存储元数据,并且会有某种引用指向包含传感器数据的文件。
不过,我仍然在考虑使用HDF5。对我来说,它有几个吸引人的地方:首先,它只是另一种文件格式,所以我不需要安装数据库管理系统,也不用去处理它的复杂性;其次,借助合适的硬件,我可以并行读写HDF5文件。(是的,我知道我也可以并行读写数据库)。
这就引出了第二点:处理非常大的数据集时,你真的需要考虑使用并行计算。我主要使用Fortran,它的一个优点是数组语法非常适合很多科学计算;另一个优点是它对并行化的支持很好。我相信Python也有各种并行化的支持,所以对你来说可能也是个不错的选择。
当然,你可以在顺序系统上添加并行性,但最好是从一开始就设计为并行处理。举个例子:一个问题的最佳顺序算法往往不是最适合并行化的算法。你可能更适合使用另一种算法,这种算法在多个处理器上扩展性更好。这自然引出了下一个要点。
我认为你可能需要接受放弃对一些聪明的算法和数据结构的依赖(如果你有的话),这些算法在所有数据都能放在内存中时效果很好。通常情况下,试图将它们适应于无法一次性将数据加载到内存中的情况,会比简单粗暴地将整个文件视为一个大数组要困难得多(而且性能也差)。
性能开始变得非常重要,包括程序的执行性能和开发者的工作效率。并不是说1TB的数据集需要10倍于1GB数据集的代码量,所以你必须工作得更快,而是你需要实现的一些想法会非常复杂,可能需要由领域专家来编写,也就是你合作的科学家们。在这里,领域专家使用Matlab进行编程。
不过,话说得有点长,我得回去工作了。