IO性能探索分析


IO性能(相對於CPU性能)探索分析

  • 體驗一:電腦經常卡頓
    • 公司發的筆記本電腦,硬件配置cpu i5六代,內存8G,機械硬盤無固態。每天編譯一個富客戶端GUI工程的時候,經常會導致電腦卡頓,CPU與內存往往都還沒有達到峰值,磁盤顯示100%

  • 體驗二:IO線程比UI線程后退出。
    • 客戶端應用在退出的時候,客戶端UI界面其實已經消失了,但是客戶端的日志文件往往在UI界面消失幾秒后才寫完——也就是IO線程比UI線程要慢好幾秒。

  • 體驗三:如下例子。(運行環境:8G內存,i5六代,固態硬盤,台式機)

  • 例一:計數10萬,計算毫秒數

    public class TestWithNoIO {
    
      public static void main(String[] args) {
    
    	long begin = System.currentTimeMillis();	
    	int i = 100000;
    	for (int j = 0; j < i; j++) {
    
    	}
    	System.out.println("testNonIO 耗時(毫秒):" + (System.currentTimeMillis() - begin));
      }
    }
    
    • 運行結果:
      testNonIO 耗時(毫秒):0
      運行許多次,數值穩定在1毫秒或者0毫秒

  • 例二:在for循環中增加System.out.print(""),注意是沒有空格的空字符串,如下:

    public class TestWithNOLR {
    
      public static void main(String[] args) {
    	long begin = System.currentTimeMillis();
    	int i = 100000;
    	for (int j = 0; j < i; j++) {
    		System.out.print("");
    	}
    	System.out.println("testIOWithNoLR 耗時:"+(System.currentTimeMillis()-begin));
      }
    }
    
    • 運行結果:
      testIOWithNoLR 耗時:13
      運行多次,數值穩定在10毫秒左右。
    • 分析:雖然實際上什么也沒有輸出,但是僅僅因為使用了IO,耗時已經明顯增加

  • 例三:這次我們在例二的基礎上,空字符串里添加一個空格。如下:

    public class TestWithNOLR {
    
      public static void main(String[] args) {
    	long begin = System.currentTimeMillis();
    	int i = 100000;
    	for (int j = 0; j < i; j++) {
    		System.out.print(" ");
    	}
    	System.out.println("testIOWithNoLR 耗時:"+(System.currentTimeMillis()-begin));
      }
    }
    
    • 運行結果:
      testIOWithNoLR 耗時:187
      運行多次,數值穩定在180毫秒左右(注意:空格輸出已被我截去)
    • 分析:IO有了實際輸出量(增加了輸出內容),耗時大大增加

  • 例四:這次在例三的基礎上,多增加一個空格。發現在例三的基礎上多了10毫秒的時間。

  • 例五:這次我們把IO由不換行的輸出字符串,改為輸出換行

    public class TestWithLR {
    
      public static void main(String[] args) {
    	long begin = System.currentTimeMillis();
    	int i = 100000;
    	for (int j = 0; j < i; j++) {
    		System.out.println();
    	}
    	System.out.println("testIOWithLR 耗時:"+(System.currentTimeMillis()-begin));
      }
    }
    
    • 運行結果:
      testIOWithLR 耗時:198
      運行多次,我們發現數值穩定在190多毫秒,基本上和例四所消耗的時間持平(也就是輸出兩個空格)。

  • 例六:這次我們在例五的基礎上增加一個換行

    public class TestWithLR {
    
      public static void main(String[] args) {
    	long begin = System.currentTimeMillis();
    	int i = 100000;
    	for (int j = 0; j < i; j++) {
    		System.out.println();
    		System.out.println();
    	}
    	System.out.println("testIOWithLR 耗時:"+(System.currentTimeMillis()-begin));
      }
    }
    
    • 運行結果:
      testIOWithLR 耗時:393
      運行多次,我們發現數值穩定在400毫秒左右。
    • 分析:換行數量翻倍以后,IO耗時翻倍。繼續增加換行,發現非常符合這個規律。

  • 以上是輸出到控制台,大家可以試一下輸出到機械硬盤,輸出到固態硬盤。

  • 總結:
    1. IO效率真的是比CPU效率低很多
    2. IO增加,耗時會增加
    3. 換行的IO增加,比不換行的IO增加,耗時明顯增加要快得多得多
  • 啟發:
    • 日志角度:
      1. 不要在生產的代碼中嵌入任何System.out.print。原因有三點,a.沒保存的日志屬於無效日志;b.性能下降(上面的例子只是以毫秒為單位);c、輸出可能重定向;
      2. 如果程序中IO比較多的時候,盡量實現IO線程和純CPU線程分離(通常的日志框架就是這么做的,例如log4j或者logback,通常是單獨的線程在運行)。占CPU的線程處理核心業務邏輯,占IO的線程處理日志或其他異步就可以完成的內容。
      3. 日志輸出盡量不要太頻繁(例如在循環中高頻輸出日志),能少一行日志就少一行日志,能少一截盡量少輸出一截(從垃圾回收角度來說也應該這么做,日志里太多字符串)
    • 數據庫角度:
      1. 設計數據庫的時候,如果有些字段可用枚舉盡量用枚舉在內存中存儲(減少磁盤IO);
      2. ……未完待續

  • 可參考資料:
    1. 一張表字段多為何要拆表:https://www.cnblogs.com/hzhuxin/p/7985452.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM