標籤:
前言
今天是五一假期第一天,按理應該是快樂玩耍的日子,但是作為一個北漂到京師的開發人員,實在難想出去那玩耍。好玩的地方比較遠,近處又感覺沒意思。於是乎,閑著寫篇文章,總結下昨天寫的程式吧。
昨天下午朋友跟我聊起,他說有個需求,需要把上G的txt檔案讀取寫入到資料庫。用普通的io結果自然是OOM了,所以果斷用NIO技術。為了提高速度,自然還得用上多線程技術。
接下來就介紹一下實現思路以及相關的知識點。
內容
一、對檔案分區
為了充分利用多線程讀取,就需要把檔案劃分成多個地區,供每個線程讀取。那麼就需要有一個演算法來計算出每個線程讀取的開始位置和結束位置。那麼首先根據配置的線程數和檔案的總長度計,算出每個線程平均分配的讀取長度。但是有一點,由於檔案是純文字檔案,必須按行來處理,如果分割點在某一行中間,那麼這一行資料就會被分成兩部分,分別由兩個線程同時處理,這種情況是不能出現的。所以各個地區的結束點上的字元必須是分行符號。第一個地區的開始位置是0,結束位置首先設為(檔案長度/線程數),如果結束點位置不是分行符號,就只能加1,直到是分行符號位置。第一個地區的結束位置有了,自然我們就能求出第二個地區的開始位置了,同理根據上邊演算法求出第二個地區的結束位置,然後依次類推第三個、第四個......
上邊的演算法中,第一個地區的結束位置定了,才能有第二個地區的開始位置,第二個地區的結束位置定了,才能有第三個地區的開始位置,依次這麼下去。照這種規律,自然地想到的是用遞迴來解決。(詳情看源碼)
二、記憶體檔案對應
簡單說一下記憶體檔案對應:
記憶體檔案對應,簡單地說就是將檔案對應到記憶體的某個地址上。 要理解記憶體檔案對應,首先得明白普通方式讀取檔案的流程: 首先記憶體空間分為核心空間和使用者空間,在應用程式讀取檔案時,底層會發起系統調用,由系統調用將資料先讀入到核心空間,然後再將資料拷貝到應用程式的使用者空間供應用程式使用。這個過程多了一個從核心空間到使用者空間拷貝的過程。 如果使用記憶體檔案對應,檔案會被映射到實體記憶體的某個地址上(不是資料載入到記憶體),此時應用程式讀取檔案的地址就是一個記憶體位址,而這個記憶體位址會被映射到了前面說到的實體記憶體的地址上。應用程式發起讀之後,如果資料沒有載入,系統調用就會負責把資料從檔案載入到這塊物理地址。應用程式便可以讀取到檔案的資料。省去了資料從核心空間到使用者空間的拷貝過程。所以速度上也會有所提高。
在我的讀取大檔案的實現中,就是用了Java的記憶體映射API,這樣我們就可以在要讀取某個地址時再將內容載入到記憶體。不需要一下子全部將內容載入進來。
總結
以上就是我主要用到的思路和一些技術點吧。可能存在某些表達不清楚的地方,望大神勿噴^_^
具體實現請參考代碼吧,這裡是代碼的地址(Java讀取大檔案)
Java多線程讀取大檔案