2011-12-16 32 views
0

考慮簡單的Java應用程序,該應用程序應該遍歷光盤中的文件樹以查找文件正文中的特定模式。在文件中查找文本模式的多線程方法

想知道是否有可能使用多線程實現更好的性能,例如,當我們找到新的文件夾時,我們會在固定的ThreadPool中提交新的Runnable。可運行的任務應該遍歷文件夾來找出新的文件夾等。我認爲這個操作應該是IO綁定,而不是CPU綁定,所以產生新的線程不會提高性能。

它取決於硬盤類型? (hdd,... etc) 它取決於操作系統類型嗎?

恕我直言,唯一可以並行的是 - 產生新的線程來解析文件內容,以找出文件正文中的模式。

什麼是解決這個問題的常見模式呢?它應該是多線程還是單線程的?

+1

這肯定取決於光盤類型...尋道時間無小事(也就是說,如果你不使用SSD),所以我沒有看到在這裏使用多線程的優勢。 考慮到了兩個文件,如果你在並行閱讀,操作系統將具有文件1讀取,然後尋求文件2,然後從文件2讀,然後...... – fge 2011-12-16 13:24:51

回答

1

您說得很對,您需要確定您的任務是CPU還是IO綁定,然後決定是否可以從多線程中獲益。一般來說,磁盤操作非常慢,因此除非您需要解析和分析複雜性的數據量,否則您可能無法從多線程中獲益太多。我只會寫一個簡單的測試 - 只是讀取不在單線程中解析的文件,測量它,然後添加解析,看看它是否慢得多,然後決定。

也許好的設計是使用兩個線程 - 一個讀取線程讀取文件並將數據放入(有界)隊列,然後另一個線程(或更好地使用ExecutorService)解析數據 - 它會給你很好的分離您可以隨時調整進行解析的線程數量。我不確定用多線程讀取磁盤是否合理(除非你需要從多個物理磁盤讀取數據)。

1

您可以做的是:實現單生產者多用戶模式,其中一個線程搜索磁盤,檢索文件,然後消費者線程處理它們。

你說得對,在這種情況下使用多個線程掃描磁盤不會有好處,事實上它可能會降低性能,因爲磁盤每次都需要尋找下一個讀取位置,所以你最終會反彈線程之間的磁盤。

2

我前一段時間做了眼前這個問題的一些實驗。最後,我總結說,通過改變我訪問文件的方式,我可以取得更好的改進。

這裏的文件沃克我終於結束了使用:

// 4k buffer size ... near-optimal for Windows. 
static final int SIZE = 4 * 1024; 

// Fastest because a FileInputStream has an associated channel. 
private static void ScanDataFile(Hunter h, FileInputStream f) throws FileNotFoundException, IOException { 
    // Use a mapped and buffered stream for best speed. 
    // See: http://nadeausoftware.com/articles/2008/02/java_tip_how_read_files_quickly 
    FileChannel ch = f.getChannel(); 
    // How much I've read. 
    long red = 0L; 
    do { 
    // How much to read this time around. 
    long read = Math.min(Integer.MAX_VALUE, ch.size() - red); 
    // Map a byte buffer to the file. 
    MappedByteBuffer mb = ch.map(FileChannel.MapMode.READ_ONLY, red, read); 
    // How much to get. 
    int nGet; 
    // Walk the buffer to the end or until the hunter has finished. 
    while (mb.hasRemaining() && h.ok()) { 
     // Get a max of 4k. 
     nGet = Math.min(mb.remaining(), SIZE); 
     // Get that much. 
     mb.get(buffer, 0, nGet); 
     // Offer each byte to the hunter. 
     for (int i = 0; i < nGet && h.ok(); i++) { 
     h.check(buffer[i]); 
     } 
    } 
    // Keep track of how far we've got. 
    red += read; 
    // Stop at the end of the file. 
    } while (red < ch.size() && h.ok()); 
    // Finish off. 
    h.close(); 
    ch.close(); 
    f.close(); 
}