关于Java文件读取效率的一点经验
2015-05-24 23:18
351 查看
问题:
用Java读入Word Vector文件,也就是格式如下的文件
行数(n),向量维数(m)
n行,每行的结果:单词 空格 m维的向量(m个浮点型数,以空格分隔)
常规做法:
vocabulary是一个<String, Integer> 的Map,就是一个词典,存储所有的词。一个vectorsMatrix存储所有的word vector
效果:
对于一个5G的文件,在2core,4thread,8G RAM的机器上,这种方法的读取时间是20min+,btw,java command line parameters(-Xms4000m -Xmx7000m)这个java进程的cpu占用率一直在350%以上,也就是这个进程几乎耗尽了本机所有的计算资源。这是一个非常令人吃惊的结果,20min+ 对于IO是一个不可思议的时长,现在普通的机型硬盘,5G数据的读入应该是个100s左右的时间。那为什么这么慢?
1. 由于我的n是一个700w+的数据,太多的函数调用一定会带来一定的时间开销
2.String.split函数的返回值toks会触发大量内存操作,分配和gc
3.Float.parseFloat这个函数应该是一个正则表达式相关的解析,不出意外,不是O(n),并且有上billion次的调用,这也会是一个时间开销的点。
测试:
head出来了50w行做了一个测试,
源程序:11s+
去掉split:6s+
去掉parse:6s+
去掉split和parse:3s+
此处没有深究java编译过程中javac的编译优化,仅仅直观的测试了一下
优化:
第一个想法,自然是并行化,能把parse的一半时间变成原来的k分之一也是很客观的,但为什么读入过程中CPU被占满了?
唯一合理的解释gc,于是优化gc相关的东西,这时候关注点基本是集中在想办法替换掉split上。但凭着直觉,把vocabulary相关的操作放到一个独立的循环里面了,因为对于C系列程序if else对流水线和预取是不怎么友好的。测试了一下,直接提高到3min以内!!!简直亮瞎!!!那么,为什么会提高呢?
原因:java HashMap会带来大量的gc操作,在你不断添加元素的过程中,它至少会分配大的空间,释放原来的空间,当你的map很大之后,这是一笔非常可观的开销。尤其是当两份数据同时存在的时候,会超过7000m的上限,引起内存和swap的交换。
用Java读入Word Vector文件,也就是格式如下的文件
行数(n),向量维数(m)
n行,每行的结果:单词 空格 m维的向量(m个浮点型数,以空格分隔)
常规做法:
File file=new File(infname); if(file.isFile() && file.exists()){ InputStreamReader read = new InputStreamReader(new FileInputStream(file), "UTF-8"); BufferedReader bufferedReader = new BufferedReader(read); String lineTxt = null; for(int i = -1; (lineTxt = bufferedReader.readLine()) != null; i++){ String[] toks = lineTxt.split(" "); if(i == -1){ if(toks.length != 2){ System.err.println("word vector start with unexpected line: " + lineTxt); bufferedReader.close(); return false; } wordsCount = Integer.parseInt(toks[0]); dimension = Integer.parseInt(toks[1]); vectorsMatrix = new float[wordsCount][dimension]; }else { if(toks.length != dimension + 1){ System.err.println("unexpected word vector: " + lineTxt + " at: " + i); bufferedReader.close(); return false; } vocabulary.put(toks[0], i); for(int j = 0; j < dimension; j++) vectorsMatrix[i][j] = Float.parseFloat(toks[j + 1]); } } bufferedReader.close(); return true; }
vocabulary是一个<String, Integer> 的Map,就是一个词典,存储所有的词。一个vectorsMatrix存储所有的word vector
效果:
对于一个5G的文件,在2core,4thread,8G RAM的机器上,这种方法的读取时间是20min+,btw,java command line parameters(-Xms4000m -Xmx7000m)这个java进程的cpu占用率一直在350%以上,也就是这个进程几乎耗尽了本机所有的计算资源。这是一个非常令人吃惊的结果,20min+ 对于IO是一个不可思议的时长,现在普通的机型硬盘,5G数据的读入应该是个100s左右的时间。那为什么这么慢?
1. 由于我的n是一个700w+的数据,太多的函数调用一定会带来一定的时间开销
2.String.split函数的返回值toks会触发大量内存操作,分配和gc
3.Float.parseFloat这个函数应该是一个正则表达式相关的解析,不出意外,不是O(n),并且有上billion次的调用,这也会是一个时间开销的点。
测试:
head出来了50w行做了一个测试,
源程序:11s+
去掉split:6s+
去掉parse:6s+
去掉split和parse:3s+
此处没有深究java编译过程中javac的编译优化,仅仅直观的测试了一下
优化:
第一个想法,自然是并行化,能把parse的一半时间变成原来的k分之一也是很客观的,但为什么读入过程中CPU被占满了?
唯一合理的解释gc,于是优化gc相关的东西,这时候关注点基本是集中在想办法替换掉split上。但凭着直觉,把vocabulary相关的操作放到一个独立的循环里面了,因为对于C系列程序if else对流水线和预取是不怎么友好的。测试了一下,直接提高到3min以内!!!简直亮瞎!!!那么,为什么会提高呢?
原因:java HashMap会带来大量的gc操作,在你不断添加元素的过程中,它至少会分配大的空间,释放原来的空间,当你的map很大之后,这是一笔非常可观的开销。尤其是当两份数据同时存在的时候,会超过7000m的上限,引起内存和swap的交换。
相关文章推荐
- 关于VC数据库开发中数据库连接与效率的问题-----一点体会和经验
- 关于java 读取propterties 文件的疑惑 和问题的解决
- 关于文件读取的一点小问题
- 关于C 和 python读取文件的效率比较
- java读取文件效率问题
- java读取文件效率问题
- Java关于读取配置文件Parsing failed.的问题org.logicalcobwebs.proxool.ProxoolException: Parsing failed.
- 关于java session监听器的一点学习经验(1)
- 关于Excel文件读取的效率问题
- 关于java读取properties文件的路径问题
- 关于java读取远程文件时网络超时判断
- 关于JAVA读取远程文件,文件地址带有空格,%百分号时报空指针问题
- 关于java读取文件时遇到Unicode乱码情况
- 关于Java读取和编写BMP文件的总结
- [转]关于java文件读写、字节流、字符流的一点新得
- 关于java读取和写入properties配置文件的内容
- 关于java读取properties文件的路径问题
- 关于Netbean Java程序下面读取记事本文件中文乱码
- 关于命令行环境执行有包结构的java文件不成功的一点点经验
- 关于android的2.2与4.4的文件读取的一点发现