Runtime.exec使用錯誤導致延遲

這篇文章是紀錄了一個bug解決的過程,但是我還是沒有能夠真正地找出bug的緣由。希望大牛能夠詳細解釋。

問題的發現

當接觸的系統越來越大的時候,對於系統的性能越來越高的時候,找到表面問題的真正原因就慢慢地成爲了一個比較麻煩的問題。說實話,一開始我一直不知道是因爲Runtime.getRuntime().exec()導致服務處理時間緩慢。發現這個原因倒是花了不少時間。

爲了方便,我直接就用java調用python腳本。用python腳本處理做核心的機器學習算法的東西。而java調用python腳本,我直接就採用了Runtime.getRuntime().exec(),這個方式類似於直接使用了shell來執行。一開始使用的挺好,也沒有注意一些細節的問題,慢慢地用着用着,發現有一臺機器處理相同地人臉頭像比另外一臺慢。從經驗上考慮過很多的可能情況,但是都不是問題的真正原因。但每一個誤判,我感覺都非常值得反思。

網絡問題

由於我使用了內網穿透工具,本身對工具性能也不熟悉,剛開始的時候立刻就想到了是不是因爲使用了內網穿透工具,導致網速太慢了。由於這個問題我幾乎就無法解決,所以我一想到這個原因,就沒有再去想辦法解決了。後面直接發現直接從訪問的結果仍然是一樣的慢。其實這個地方我應該去驗證一下,直接從內網訪問,看一下速度。這樣就能夠避免誤判帶來的問題了。

機器配置問題

由於兩臺機器配置的時候還是存在一點點不同,我後面又想是不是一臺機器配置出現問題?檢查了半天還是不能確認是不是機器配置不同,安裝的內容不同導致出現了問題。由於沒什麼時間,乾脆我又扔一邊去了。

某些隨機因素

因爲一臺機器執行快速,另外一臺執行緩慢,而出現這種詭異的問題,很容易就讓人想到是不是代碼庫因爲某些原因,導致了這種情況。而往往這種問題就基本是沒有辦法搞定了。其實我還是一個新手的時候,我總是懷疑某些問題是因爲一些系統錯誤,隨機因素導致的。但是結果往往是自己的錯誤。因爲有了之前的經驗,我潛意識就感覺可能是自己哪段代碼出現了錯誤。

之後通過對代碼片段打印時間,每一段執行完都打印時間點。最後查看日誌發現,就是在調用process.waitfor的時候,python程序已經返回了,但是java程序仍然沒有任何響應,還是在wait。這樣才發現了這個問題。然後通過在網上搜索Runtime.getRuntime()執行程序應該注意的事項,找到問題的關鍵。我使用waitfor,之後再去讀取python程序的輸出,但是因爲輸出一直沒有被讀取,緩衝區滿了,程序就被阻塞。

getRuntime().exec

getRuntime().exec會返回一個Process,在jdk文檔中有說明,Process的緩衝區是有限的,如果輸出的內容太多,程序就會被阻塞掉。
我一開始的程序是像下面這樣的:

​    ​try {          
​    ​         final Process p = Runtime.getRuntime().exec("python test.py");
​    ​    ​    ​ p.waitFor();       
​    ​         BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
​    ​         try {
​    ​                      while (br.readLine() != null)
​    ​                          ;
​    ​                      br.close();
​    ​          } catch (IOException e) {
​    ​               e.printStackTrace();
​    ​          }
​    ​} catch (Exception e) {
​    ​          e.printStackTrace();      
​    ​}

這樣的結果就是一臺機器在waitFor那裏被卡住很長一段時間。然後參考了網上給的原因,將程序改成下面這樣:

    try {          
             final Process p = Runtime.getRuntime().exec("python test.py");

             BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
             try {
                          while (br.readLine() != null)
                              ;
                          br.close();
              } catch (IOException e) {
                   e.printStackTrace();
              }
              p.waitFor();  
    } catch (Exception e) {
              e.printStackTrace();      
    }

這樣程序就不會長時間卡在那裏。甚至於去掉p。waitFor程序也是OK的。因爲程序結束後,Stream就被close掉了。網上很多人是遇到了因爲exec執行的程序出現了錯誤,結果Error信息佔滿了緩衝區,導致程序被掛起。

原因探究

從網上看的那些信息只能讓我猜測可能是因爲打印信息太多,沒有及時讀出,導致程序卡住。但是我心裏還是有疑問,爲什麼一臺機器ok,另外一臺機器會卡住,過很長時間才返回呢?這裏面具體的細節方面的原因我覺得我還是沒有找對。其實我python程序打印的東西也不多的。

另外也有一個可能是python程序執行完後,很長時間都沒有完全返回。這也是一個猜測的原因。雖然我按照網上的方式暫時解決了問題,但這些原因其實我覺得都不夠充分,希望有人能夠給出正確的解釋。基礎真的要牢靠。

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