前回StringTemplateの記事を書きましたが、Apache Velocityと性能を比べてみました。
Apache Velocityではまったこと
テンプレートの書き方を忘れていて、テンプレートで変数のプロパティを指定する場合getterが必要でした。。
例えば、Apache Velocityのテンプレートで、${obj.value01}とした場合、プログラム内では、public変数の"public String value01;" では駄目で、メソッドの "public String getValue01() "が必要となります。
(まぁ、Javaコードならgetterは作るとは思いますが、こういう点では「StringTemplate」の柔軟さはいいですね。)
比較結果
出力の時間を比較してみました。
結論としては「Apache Velocity」が早いです。1回目と2回目はちょっと遅いですが、その後の性能が「String Template」の半分の時間で終わっています。扱う件数が1億件とかになってくるとこの処理時間の差で1日ぐらいの差となります。
実行回数 | StringTemlate | Apache Velocity | 差(A-B) |
ナノ秒(A) | ナノ秒(B) | ||
1 | 8,810,818 | 22,477,063 | -13,666,245 |
2 | 2,216,037 | 2,628,724 | -412,687 |
3 | 1,696,282 | 728,150 | 968,132 |
4 | 1,775,865 | 653,078 | 1,122,787 |
5 | 1,458,761 | 719,125 | 739,636 |
6 | 1,586,751 | 516,474 | 1,070,277 |
7 | 1,512,911 | 408,584 | 1,104,327 |
8 | 1,441,531 | 471,759 | 969,772 |
9 | 1,192,115 | 471,759 | 720,356 |
10 | 1,180,628 | 430,326 | 750,302 |
2から10の平均 | 1,562,320 | 780,887 | 781,434 |
Apache Velocityのテンプレート
StringTemplateと同様のものをVTLで書きました。「Apache Velocity」のバージョンは1.7を使います。
${callcnt} 回目の出力
変数の差込10個
01 ${value01}
02 ${value02}
03 ${value03}
04 ${value04}
05 ${value05}
06 ${value06}
07 ${value07}
08 ${value08}
09 ${value09}
10 ${value10}
プロパティの差込10個 (1段階)
01 ${obj.value01}
02 ${obj.value02}
03 ${obj.value03}
04 ${obj.value04}
05 ${obj.value05}
06 ${obj.value06}
07 ${obj.value07}
08 ${obj.value08}
09 ${obj.value09}
10 ${obj.value10}
プロパティの差込10個 (2段階)
01 ${obj.prop.value01}
02 ${obj.prop.value02}
03 ${obj.prop.value03}
04 ${obj.prop.value04}
05 ${obj.prop.value05}
06 ${obj.prop.value06}
07 ${obj.prop.value07}
08 ${obj.prop.value08}
09 ${obj.prop.value09}
10 ${obj.prop.value10}
ループ(要素10)
#foreach( $row in $rows )
${row.rownum} ${row.value}
#end
そして性能を算出したプログラムは次です。
通常「Apache Velocity」はテンプレートファイルから読み込むのですが、「String Template」と同様にテンプレートの文字列から変数を展開するように書いています。
import java.io.File;
import java.io.FileInputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.text.DecimalFormat;
import java.util.ArrayList;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.runtime.RuntimeServices;
import org.apache.velocity.runtime.RuntimeSingleton;
import org.apache.velocity.runtime.parser.ParseException;
import org.apache.velocity.runtime.parser.node.SimpleNode;
public class VelocitySample {
public static void main(String... args) throws Exception{
DecimalFormat df = new DecimalFormat("000000");
Template vt = null;
long templatestart = System.nanoTime();
vt = newTemplate(templateStr());
long templateend = System.nanoTime();
System.out.println(templateend - templatestart);
for( int i=1; i<=1000 ; i++) {
long bindstart = System.nanoTime();
new VelocitySample().execute(vt ,i);
long bindend = System.nanoTime();
System.out.println( df.format(i) + "回目:" + (bindend - bindstart));
}
}
public static Template newTemplate(String templateString) throws Exception{
/** このように書くことでテンプレートの文字列を内部でコンパイルする **/
RuntimeServices runtimeServices = RuntimeSingleton.getRuntimeServices();
StringReader reader = new StringReader(templateString);
SimpleNode node;
try {
node = runtimeServices.parse(reader, "template1");
} catch (ParseException e) {
throw new RuntimeException("パースエラー", e);
}
Template template = new Template();
template.setRuntimeServices(runtimeServices);
template.setData(node);
template.initDocument();
return template;
}
public void execute(Template vt , int callcnt) throws Exception{
String rnd = ":" + (int)(Math.random() * 10000);
String value01 = "value01"+rnd;
String value02 = "value02"+rnd;
String value03 = "value03"+rnd;
String value04 = "value04"+rnd;
String value05 = "value05"+rnd;
String value06 = "value06"+rnd;
String value07 = "value07"+rnd;
String value08 = "value08"+rnd;
String value09 = "value09"+rnd;
String value10 = "value10"+rnd;
Class1 c1 = new Class1();
c1.value01 = "nest1obj." + value01;
c1.value02 = "nest1obj." + value02;
c1.value03 = "nest1obj." + value03;
c1.value04 = "nest1obj." + value04;
c1.value05 = "nest1obj." + value05;
c1.value06 = "nest1obj." + value06;
c1.value07 = "nest1obj." + value07;
c1.value08 = "nest1obj." + value08;
c1.value09 = "nest1obj." + value09;
c1.value10 = "nest1obj." + value10;
c1.prop.value01 = "nest21obj." + value01;
c1.prop.value02 = "nest21obj." + value02;
c1.prop.value03 = "nest21obj." + value03;
c1.prop.value04 = "nest21obj." + value04;
c1.prop.value05 = "nest21obj." + value05;
c1.prop.value06 = "nest21obj." + value06;
c1.prop.value07 = "nest21obj." + value07;
c1.prop.value08 = "nest21obj." + value08;
c1.prop.value09 = "nest21obj." + value09;
c1.prop.value10 = "nest21obj." + value10;
ArrayList<Class2> rows = new ArrayList<>();
for(int i=1; i<=10; i++){
Class2 c2 = new Class2();
c2.rownum = i;
c2.value = "loopvalue" + rnd;
rows.add(c2);
}
VelocityContext vc = new VelocityContext();
vc.put("callcnt",callcnt );
vc.put("value01",value01 );
vc.put("value02",value02 );
vc.put("value03",value03 );
vc.put("value04",value04 );
vc.put("value05",value05 );
vc.put("value06",value06 );
vc.put("value07",value07 );
vc.put("value08",value08 );
vc.put("value09",value09 );
vc.put("value10",value10 );
vc.put("obj", c1);
vc.put("rows", rows);
StringWriter writer = new StringWriter();
vt.merge( vc , writer);
String ret = writer.toString();
}
public class Class1{
public String getValue01() {
return value01;
}
public void setValue01(String value01) {
this.value01 = value01;
}
public String getValue02() {
return value02;
}
public void setValue02(String value02) {
this.value02 = value02;
}
public String getValue03() {
return value03;
}
public void setValue03(String value03) {
this.value03 = value03;
}
public String getValue04() {
return value04;
}
public void setValue04(String value04) {
this.value04 = value04;
}
public String getValue05() {
return value05;
}
public void setValue05(String value05) {
this.value05 = value05;
}
public String getValue06() {
return value06;
}
public void setValue06(String value06) {
this.value06 = value06;
}
public String getValue07() {
return value07;
}
public void setValue07(String value07) {
this.value07 = value07;
}
public String getValue08() {
return value08;
}
public void setValue08(String value08) {
this.value08 = value08;
}
public String getValue09() {
return value09;
}
public void setValue09(String value09) {
this.value09 = value09;
}
public String getValue10() {
return value10;
}
public void setValue10(String value10) {
this.value10 = value10;
}
public Nest1 getProp() {
return prop;
}
public void setProp(Nest1 prop) {
this.prop = prop;
}
public String value01;
public String value02;
public String value03;
public String value04;
public String value05;
public String value06;
public String value07;
public String value08;
public String value09;
public String value10;
public Nest1 prop = new Nest1();
}
public class Nest1{
public String getValue01() {
return value01;
}
public void setValue01(String value01) {
this.value01 = value01;
}
public String getValue02() {
return value02;
}
public void setValue02(String value02) {
this.value02 = value02;
}
public String getValue03() {
return value03;
}
public void setValue03(String value03) {
this.value03 = value03;
}
public String getValue04() {
return value04;
}
public void setValue04(String value04) {
this.value04 = value04;
}
public String getValue05() {
return value05;
}
public void setValue05(String value05) {
this.value05 = value05;
}
public String getValue06() {
return value06;
}
public void setValue06(String value06) {
this.value06 = value06;
}
public String getValue07() {
return value07;
}
public void setValue07(String value07) {
this.value07 = value07;
}
public String getValue08() {
return value08;
}
public void setValue08(String value08) {
this.value08 = value08;
}
public String getValue09() {
return value09;
}
public void setValue09(String value09) {
this.value09 = value09;
}
public String getValue10() {
return value10;
}
public void setValue10(String value10) {
this.value10 = value10;
}
public String value01;
public String value02;
public String value03;
public String value04;
public String value05;
public String value06;
public String value07;
public String value08;
public String value09;
public String value10;
}
public class Class2 {
public int getRownum() {
return rownum;
}
public void setRownum(int rownum) {
this.rownum = rownum;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public int rownum;
public String value;
}
public static String templateStr() throws Exception{
File t = new File("template1.txt");
byte[] bytes = new byte[(int)t.length()];
FileInputStream fis = new FileInputStream(t);
fis.read(bytes);
fis.close();
return new String(bytes, "Windows-31J");
}
}
setter/getterを追加しているのもそうですが、「Apache Velocity」用のコードだけでも多いですね。