android 下Protobuff經常使用的框架有三個: protobuff自身, square出的wire , protostuffandroid
因爲protobuff會爲每一個屬性生成大量不經常使用的方法,當程序比較複雜時容易超過android的60K個方法的上限, 因此本次測試未包括protobuffgit
測試邏輯是循環100次序列化100個元素的數組,並反序列化,求平均值,代碼以下:github
wire的測試代碼:數組
public void onClickButton(View view){ if (TestTask.isCancel){ TestTask.isCancel = false; TestTask.sumDeserializeTime = 0; TestTask.sumTime = 0; TestTask.runCount = 0; TextView text1 = (TextView) findViewById(R.id.textView2); text1.setText(""); new TestTask( (TextView) findViewById(R.id.textView2) , (TextView) findViewById(R.id.button1)).execute(); ((TextView)view).setText("測試中,點擊中斷"); }else{ ((TextView)view).setText("正在中斷..."); TestTask.isCancel = true; } } static class TestTask extends AsyncTask<Void,Void,Long>{ long serializeTime=0; long deserializeTime=0; static long sumTime=0; static long sumDeserializeTime=0; static int runCount=0; static boolean isCancel=true; TextView text1; TextView btn; public TestTask(TextView text1,TextView btn) { this.text1 = text1; this.btn = btn; } @Override protected Long doInBackground(Void... params) { long startTime = System.currentTimeMillis(); for (int i = 0; i < 100; i++) { List<ListItem> itemList = new ArrayList<ListItem>(); ListItem.Builder itemBuilder = new ListItem.Builder(); ListItem item; for (int j = 0; j < 100; j++) { item = itemBuilder.title("test Title"+i+":"+j) .remark("test Remark"+i+":"+j) .coverUrl("http://pic.ozreader.com/abc.pic") .uri("PKB:TESTURI") .build(); itemList.add(item); } ScrollList.Builder listBuilder= new ScrollList.Builder(); ScrollList list = listBuilder.haveMore(false).tags(itemList).build(); byte[] dataBuffer = list.toByteArray(); serializeTime = System.currentTimeMillis()-startTime; Wire wire = new Wire(); try { ScrollList resultList = wire.parseFrom(dataBuffer, ScrollList.class); if (resultList == null){ Log.e("TEST", "resultList is null"); break; }else if (resultList.tags == null){ Log.e("TEST", "resultList.tags is null"); break; }else if (resultList.tags.size() <= 0){ Log.e("TEST", "resultList.tags is empty"); break; }else if (resultList.tags.size() != 100){ Log.e("TEST", "resultList.tags is wrong"); break; }else if (!resultList.tags.get(0).uri.equals("PKB:TESTURI")){ Log.e("TEST", "resultList.tags content is wrong"); break; } deserializeTime = System.currentTimeMillis()-startTime-serializeTime; } catch (IOException e) { e.printStackTrace(); } } return System.currentTimeMillis() - startTime; } @Override protected void onPostExecute(Long result) { sumTime += result; sumDeserializeTime += deserializeTime; runCount ++; text1.append("result:"+result+", serializeTime:"+serializeTime+", deserializeTime:"+deserializeTime+", runCount:"+runCount+", avg:"+sumTime/runCount+", avg deserializeTime:"+sumDeserializeTime/runCount+"\n"); if (isCancel){ text1.append("測試中斷."); btn.setText("開始測試"); }else if (runCount < 100){ new TestTask(text1,btn).execute(); }else{ isCancel = true; text1.append("測試完成."); btn.setText("開始測試"); } } }
protobuff的測試代碼:app
public void onClickButton(View view){ if (TestTask.isCancel){ TestTask.isCancel = false;
TestTask.sumDeserializeTime = 0;
TestTask.sumTime = 0;
TestTask.runCount = 0;
TextView text1 = (TextView) findViewById(R.id.textView2);
text1.setText(""); new TestTask( (TextView) findViewById(R.id.textView2) , (TextView) findViewById(R.id.button1)).execute(); ((TextView)view).setText("測試中,點擊中斷"); }else{ ((TextView)view).setText("正在中斷..."); TestTask.isCancel = true; } } static class TestTask extends AsyncTask<Void,Void,Long>{ long serializeTime=0; long deserializeTime=0; static long sumTime=0; static long sumDeserializeTime=0; static int runCount=0; static boolean isCancel=true; TextView text1; TextView btn; public TestTask(TextView text1,TextView btn) { this.text1 = text1; this.btn = btn; } @Override protected Long doInBackground(Void... params) { long startTime = System.currentTimeMillis(); for (int i = 0; i < 100; i++) { List<ListItem> itemList = new ArrayList<ListItem>(); ScrollList list = new ScrollList(); list.setHaveMore(false); list.setTagsList(itemList); ListItem item; for (int j = 0; j < 100; j++) { item = new ListItem(); item.setTitle("test Title"+i+":"+j); item.setRemark("test Remark"+i+":"+j); item.setCoverUrl("http://pic.ozreader.com/abc.pic"); item.setUri("PKB:TESTURI"); itemList.add(item); } LinkedBuffer buffer = LinkedBuffer.allocate(1024); byte[] dataBuffer = ProtobufIOUtil.toByteArray(list, ScrollList.getSchema(), buffer); serializeTime = System.currentTimeMillis()-startTime; ScrollList resultList = new ScrollList(); ProtobufIOUtil.mergeFrom(dataBuffer, resultList, ScrollList.getSchema()); if (resultList.getTagsList() == null){ Log.e("TEST", "resultList.tags is null"); break; }else if (resultList.getTagsList().size() <= 0){ Log.e("TEST", "resultList.tags is empty"); break; }else if (resultList.getTagsList().size() != 100){ Log.e("TEST", "resultList.tags is wrong"); break; }else if (!resultList.getTagsList().get(0).getUri().equals("PKB:TESTURI")){ Log.e("TEST", "resultList.tags content is wrong"); break; } deserializeTime = System.currentTimeMillis()-startTime-serializeTime; } return System.currentTimeMillis() - startTime; } @Override protected void onPostExecute(Long result) { sumTime += result; sumDeserializeTime += deserializeTime; runCount ++; text1.append("result:"+result+", serializeTime:"+serializeTime+", deserializeTime:"+deserializeTime+", runCount:"+runCount+", avg:"+sumTime/runCount+", avg deserializeTime:"+sumDeserializeTime/runCount+"\n"); if (isCancel){ text1.append("測試中斷."); btn.setText("開始測試"); }else if (runCount < 100){ new TestTask(text1,btn).execute(); }else{ isCancel = true; text1.append("測試完成."); btn.setText("開始測試"); } } }
測試結果爲(單位豪秒):框架
手機環境:魅族MX2ide
1) wire 1.5.1 ,網址 https://github.com/square/wire
性能
avg: 1860~1907 , 最小值約爲1500左右,極少出現, 全過程隨機分佈測試
avg deserializeTime: 9~10, 最小值約爲5,極少出現,全過程隨機分佈ui
2) protostuff 1.0.8 ,網址 https://code.google.com/p/protostuff/
avg: 1100~1150,很是穩定 , 最小值約爲450左右,主要集中在前幾回循環,循環10次後就穩定在11XX左右,偶有600~800的狀況,屢次重複測試狀況基本一致,觀察自動GC並沒有內存泄漏的問題, 暫時不肯定速度變化的緣由.
avg deserializeTime: 6, 最小值約爲3,極少出現,主要集中在剛開始,絕大多數爲5,偶有達到16的狀況.
分析: wire的性能明顯比不上protostuff, 速度也不太穩定,起落較大. 考慮到protostuff的開發模式是普通的pojo方式,比較方便,不像protobuff和wire的builder方式,超麻煩. 因此最終推薦不是邏輯超複雜的企業app都使用protostuff .