2011-07-11 23 views
8

我的任務是讀取大型CSV文件(300k +記錄)並將正則表達式模式應用於每條記錄。我一直是一名PHP開發人員,從來沒有真正嘗試過任何其他語言,但決定我應該深入研究,並嘗試使用Java來實現這一點,我認爲這會更快。比預期的Java正則表達式更慢

實際上,只是逐行讀取CSV文件的速度是Java的3倍。但是,當我應用正則表達式要求時,Java實現證明比PHP腳本長10-20%。

我在Java中做了錯誤的事情的可能性很大,因爲我剛剛在今天去了解了這一點。以下是兩個腳本,任何建議將不勝感激。我真的不想放棄Java這個特定的項目。

PHP代碼

<?php 
$bgtime=time(); 
$patterns =array(
    "/SOME REGEXP/", 
    "/SOME REGEXP/",      
    "/SOME REGEXP/",  
    "/SOME REGEXP/" 
); 

$fh = fopen('largeCSV.txt','r'); 
while($currentLineString = fgetcsv($fh, 10000, ",")) 
{ 
    foreach($patterns AS $pattern) 
    { 
     preg_match_all($pattern, $currentLineString[6], $matches); 
    } 
} 
fclose($fh); 
print "Execution Time: ".(time()-$bgtime); 

?> 

Java代碼

import au.com.bytecode.opencsv.CSVReader; 
import java.io.FileReader; 
import java.io.IOException; 
import java.util.regex.Pattern; 
import java.util.regex.Matcher; 
import java.util.ArrayList; 

public class testParser 
{ 
    public static void main(String[] args) 
    { 
     long start = System.currentTimeMillis(); 


     String[] rawPatterns = { 
        "SOME REGEXP", 
        "SOME REGEXP",      
        "SOME REGEXP",  
        "SOME REGEXP"  
     }; 

     ArrayList<Pattern> compiledPatternList = new ArrayList<Pattern>();   
     for(String patternString : rawPatterns) 
     { 
      Pattern compiledPattern = Pattern.compile(patternString); 
      compiledPatternList.add(compiledPattern); 
     } 


     try{ 
      String fileName="largeCSV.txt"; 
      CSVReader reader = new CSVReader(new FileReader(fileName)); 

      String[] header = reader.readNext(); 
      String[] nextLine; 
      String description; 

      while((nextLine = reader.readNext()) != null) 
      { 
       description = nextLine[6]; 
       for(Pattern compiledPattern : compiledPatternList) 
       { 
        Matcher m = compiledPattern.matcher(description); 
        while(m.find()) 
        { 
         //System.out.println(m.group(0)); 
        }     
       } 
      } 
     } 

     catch(IOException ioe) 
     { 
      System.out.println("Blah!"); 
     } 

     long end = System.currentTimeMillis(); 

     System.out.println("Execution time was "+((end-start)/1000)+" seconds."); 
    } 
} 
+0

與您的正則表達式問題不完全相關,但您可能需要查看http://download.oracle.com/javase/6/docs/api/java/util/Scanner.html。你可能會發現你的CSVReader類是不需要的。不創建所有這些臨時字符串('nextLine'似乎至少有7個字符串,但只需要一個)可能會提高性能。 – wolfcastle

回答

3

我看不出什麼錯得離譜與您的代碼。嘗試使用探查器來隔離性能瓶頸。我發現netbeans profiler非常用戶友好。

編輯:爲什麼猜測?對應用進行簡介並獲取詳細的時間消耗報告。然後努力解決低效率的領域。有關更多信息,請參閱http://profiler.netbeans.org/。編輯2:好吧,我覺得無聊,並描繪了這一點。我的代碼是相同的你和解析的CSV文件有如下1000個相同的行:

SOME REGEXP,SOME REGEXP,SOME REGEXP,SOME REGEXP,SOME REGEXP,SOME REGEXP,SOME REGEXP,SOME REGEXP,SOME REGEXP,SOME REGEXP 

下面是結果(當然你的結果會有所不同我的正則表達式是微不足道的)。然而,很明顯看到正則表達式處理並不是你關心的主要領域。

enter image description here

有趣的是,如果我申請一個BufferedReader,性能受到高達18%提高(見下文)。這裏要注意

enter image description here

+0

剛剛在Notepad ++中加了這個,但是我會給netbeans一個去看看它的含義。 – IOInterrupt

+0

顯然我不知道如何有效地利用分析器。我已經對我的JAVA應用程序運行了剖析器,但它似乎顯示了內存(堆),內存(GC)和線程/加載類...以及main()的執行時間。有沒有什麼好的教程如何利用這個? – IOInterrupt

+0

@IOInterrupt - 在Netbeans中,配置文件>配置文件主項目> CPU>整個應用程序>運行 – hoipolloi

0

幾點。

  1. 即使在編譯模式之前,您也開始測量時間。 Pattern.compile是一個相對昂貴的操作,如果模式複雜,可能會消耗更多時間。爲什麼不在編譯步驟之後開始測量?

  2. 我不確定CSVReader類是多麼有效率。

  3. 而不是直接在主線程本身打印匹配結果(因爲System.out.println阻塞和昂貴),您可能可能委託打印到不同的線程。

+1

我更喜歡從開始的時候開始編寫腳本,因爲這兩個腳本基本上都在做同樣的事情,我認爲腳本執行時間總是一個有效的指標。 我認爲正則表達式的複雜性是問題,所以我將它們全部改爲單個常用詞。 PHP的執行時間是93秒,而Java的是246秒。我相信CSVReader類是高效的,因爲它能夠比PHP fgetcsv()函數更快地讀取CSV文件(速度提高3倍)。另外,我已經註釋掉了println()函數。 – IOInterrupt

+0

@IOInterrupt:對。有很多因素可以在這裏發揮作用。輸入到虛擬機的內存量也起着主要作用。你可以嘗試按照hoipolloi的建議分析應用程序。 – adarshr

+0

談到VM時,我很無知。我很高興得到這個東西的工作。 – IOInterrupt

0

幾件事情:

  1. 正則表達式,必須一次編譯,這應該是在服務器的啓動等等都無所謂了,而它的運行性能。

  2. 而最重要的是,你正在爲長期運行的java程序編寫一個完全無效的基準。你肯定會加載幾個課程,而基準測試和整體只測試解釋器的性能,而不是JIT,這顯然會導致更糟的性能。有關如何在java中編寫有效的基準測試,請參閱this出色的文章。在這種情況下,這肯定會彌補所有性能問題。

+2

OP沒有說有一臺服務器,也沒有說它是一個長時間運行的程序。可能是這種情況,你會是對的,但它可能不是。 –

+1

假設這是一臺服務器,因爲他使用的是PHP,但是您是對的。但是如果程序運行時間不長而且性能不重要,爲什麼地獄會關心優化呢? – Voo

+0

正如手動運行JAVA應用程序一樣,PHP腳本通過PHP CLI手動運行。我不確定這是否會影響你的建議。處理500MB CSV文件時,這兩個腳本運行約10分鐘。 – IOInterrupt

4

使用緩衝讀者可能有助於表現得相當好一點:

CSVReader reader = new CSVReader(new BufferedReader(new FileReader(fileName))); 
+0

良好的捕捉,如果FileReader不緩衝自己,這肯定是性能瓶頸。 – Voo

+0

CSVReader是否緩衝。 –

+0

這給了一個小小的增加,但不是魔術醬。感謝您的建議,但! – IOInterrupt

0

我會建議:

  • 爲別人曾建議,個人資料上看到實際的瓶頸是;
  • 告訴我們實際的正則表達式是什麼:它可能是因爲你正在使用一些在Java實現中效率不高的特定子模式。

很可能PHP的正則表達式引擎的某些部分比Java對特定表達式類型更優化,或者有一種方法可以優化您正在使用的實際表達式。