[介绍]
Groovy File.append很慢,因为每次都要打开/关闭文件。如果你的处理程序要多次append信息到文件中,那将非常非常的慢!
本文将介绍我最近在使用File.append中碰到的性能问题,以及解决的方式。
Groovy是什么?
https://en.wikipedia.org/wiki/Groovy_%28programming_language%29
http://www.groovy-lang.org/
[问题]
最近(201504)写一个文件处理程序,使用了Groovy的File.append,结果很坑人呀。一个500多兆的文件,弄了几个小时。
[原因]
使用JVisualVM一看,大部分时间在FileOutputStream.close. 找到源代码一看(源码已附上),果然啊,每次都要打开、关闭文件,那必须慢啊。
[解决方案]
直接使用java的FileWriter.append(), 而避免使用Groovy的 ResourceGroovyMethods.append()
使用更大的buffersize, BufferedOutputSteam可以提高效率. 注意: BufferedWriter不会帮助你太多,参考 [实践]Log4j 1.X BufferedIO不工作(<8k时)原因分析, 暨深入探查Java IO Output BufferSizehttp://winnerbao.iteye.com/blog/2219736
[特别提示]
当发现程序效率很低时,不要直接想当然的&急冲冲的将自己怀疑的地方改掉。再想想,并用profiling工具(推荐jvisualvm)看看, 来验证你的猜测。
此处想起某本书(Bob? Joe? 忘了)上写,“你要知道并方便的profiling你的程序”。几年前就读过,但是有什么用
我当时就犯了一个错误,想当然的以为每次写入的东西太少而引起的缓慢。然后就将文件内容缓存到StringBuilder里面,增加每次写入数量,结果“果然快了!”。当时还以为自己有点牛X。实际上是因为缓存了内容,而减少了append(即close)的次数。
[附录]
我的处理程序片段
sourceCSVDealsFile.eachLine { csvDealLine, lineNumber ->
if(lineNumber == 1){
//header
destCSVDealsFile.append(csvDealLine+"\n")
excludedCSVDealsFile.append(csvDealLine+"\n")
return
}
if(shouldBeExcluded(csvDealLine)){
excludedCSVDealsFile.append(csvDealLine+"\n")
}else{
destCSVDealsFile.append(csvDealLine+"\n")
}
}
Groovy File.append (ResourceGroovyMethods.append) 源码
http://grepcode.com/file/repo1.maven.org/maven2/com.ovea.tajin/tajin-all/1.0.b1/org/codehaus/groovy/runtime/ResourceGroovyMethods.java#ResourceGroovyMethods.append%28java.io.File%2Cjava.lang.Object%2Cjava.lang.String%29
/**
* Write the text to the File, using the specified encoding.
*
* @param file a File
* @param text the text to write to the File
* @param charset the charset used
* @throws IOException if an IOException occurs.
* @since 1.0
*/
public static void write(File file, String text, String charset) throws IOException {
BufferedWriter writer = null;
try {
writer = newWriter(file, charset);
writer.write(text);
writer.flush();
Writer temp = writer;
writer = null;
temp.close();
} finally {
closeWithWarning(writer);
}
}