flutter疑難雜症之記一次release模式和debug模式的性能差距

最近遇到一個問題,來來回回花了好幾天才解決,在此記錄一下。

 

需求是這樣的,項目中要用到圖片播放,每秒鐘大概有十幾張圖片展示,而圖片的傳輸是通過原始的socket tcp傳輸的。

由於這些tcp流是服務器推送的,涉及到拆包和拼包,具體來說服務器可能一個tcp流包含多張圖片,所以要對每張圖片進行拆包,而它每個流可能不完整,需要等到下一次的流進行拼接然後再處理。

 

bug是我在調試的時候debug模式沒有任何問題,圖片播放流暢,當我發佈版本測試的時候release模式下,圖片的播放就開始卡頓了。

 

一臉懵逼,爲啥release模式下性能反而更低呢?

 

後來仔細分析加日誌發現一個大祕密:

release模式下socket.listen的ondata回調List<int>數據是debug模式的三四倍,release模式下list的length平均爲1800000,而debug模式下list的length最大不超過600000, 這樣看起來release模式的性能還是會高很多。

 

但是問題來了,上文說過,業務涉及到拆包拼包,所以我對list進行了操作,sublist拆包,addAll拼包,在如此大的量級下,這兩個api及其耗時,平均處理每張圖片需要220多毫秒,因此會導致播放圖片卡頓。而在debug模式下,由於報文比較少,這兩個api相對沒有那麼耗時,所以處理的速度比較快,基本上包來了瞬間就拆分處理完了,因此纔有一種debug版本性能反而比release版本性能高的假象。

 

既然問題的原因已經發現了,那麼解決起來就比較簡單了,不論什麼模式,我只要將每個報文控制在一個合理的範圍內,那麼效率自然就高了。但是苦於沒有找到像c語言那樣設置tcp接收緩衝區大小的api,因此,我不得不對報文進行一個拆分處理,每個報文拆分成1024 * 256這麼長的一小段(這個長度實驗了好久,跟具體業務有關),用for循環去處理,運行發現圖片在release模式下也能夠流暢的運行了。。

 

爲了更加直觀的看到性能差距,我寫了一個測試代碼。

import 'package:flutter/material.dart';

class TestPage extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return Container(child: FlatButton(onPressed: (){
      handleList();
      handleList2();
    }, child: Center(child: Text("onPress"),)), color: Colors.green,);
  }


  void handleList(){
    List<int> list = createList(2000000);
    List<int> lastRemain = List();
    int perLength = 100001;
    int count = 0;
    print("***************************************************");
    int startTime = DateTime.now().millisecondsSinceEpoch;
    lastRemain.addAll(list);
    while(true){
      if(lastRemain.length < perLength){
        break;
      }
      List<int> cur = lastRemain.sublist(0, perLength);
      lastRemain = lastRemain.sublist(cur.length);
      count++;
    }
    print("count = $count  cost = ${DateTime.now().millisecondsSinceEpoch - startTime}");
  }

  void handleList2(){
    List<int> list = createList(2000000);
    int length = list.length;
    List<int> lastRemain = List();
    int segLength = 1024 * 256;
    int perLength = 100001;
    int count = 0;
    print("------------------------------------------");
    int startTime = DateTime.now().millisecondsSinceEpoch;
    for(int i = 0; i < length; i += segLength) {
      List<int> seg = list.sublist(i, i+segLength>length?length:i+segLength);
      lastRemain.addAll(seg);
      while(true){
        if(lastRemain.length < perLength){
          break;
        }
        List<int> cur = lastRemain.sublist(0, perLength);
        lastRemain = lastRemain.sublist(cur.length);
        count++;
      }
    }
    print("count = $count  cost = ${DateTime.now().millisecondsSinceEpoch - startTime}");
    print("***************************************************");
  }

  List<int> createList(int n){
    List<int> list = List();
    for(int i=0; i<n; i++){
      list.add(i);
    }
    return list;
  }

}

代碼比較簡單,但是也能說明問題。handleList是我們直接處理大包,handleList2是我們將大包拆分爲中包然後再處理,perLength 假設是每張圖片的大小,我們的任務是每次得到一張圖片,如果不足一張,那麼留給下次拼包處理。

運行代碼:

I/flutter (10901): ***************************************************
I/flutter (10901): count = 19  cost = 770
I/flutter (10901): ------------------------------------------
I/flutter (10901): count = 19  cost = 225
I/flutter (10901): ***************************************************
I/flutter (10901): ***************************************************
I/flutter (10901): count = 19  cost = 653
I/flutter (10901): ------------------------------------------
I/flutter (10901): count = 19  cost = 227
I/flutter (10901): ***************************************************
I/flutter (10901): ***************************************************
I/flutter (10901): count = 19  cost = 720
I/flutter (10901): ------------------------------------------
I/flutter (10901): count = 19  cost = 220
I/flutter (10901): ***************************************************

結果能夠說明問題。

如果我們將原始報文增加到6000000會怎樣呢?來看看結果吧:

I/flutter (14229): ***************************************************
I/flutter (14229): count = 59  cost = 6449
I/flutter (14229): ------------------------------------------
I/flutter (14229): count = 59  cost = 943
I/flutter (14229): ***************************************************
I/flutter (14229): ***************************************************
I/flutter (14229): count = 59  cost = 6283
I/flutter (14229): ------------------------------------------
I/flutter (14229): count = 59  cost = 932
I/flutter (14229): ***************************************************
I/flutter (14229): ***************************************************
I/flutter (14229): count = 59  cost = 6147
I/flutter (14229): ------------------------------------------
I/flutter (14229): count = 59  cost = 924
I/flutter (14229): ***************************************************

 

雖然這次的bug這樣解決了,但是感覺flutter在某些情況下性能上還是會成爲一個瓶頸,因爲我在原生的ios上面沒有發現這個bug。

 

flutter很好,路還很長,讓我們一起奮鬥前行!

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章