最近的同事的組內分享的內容就是標題的內容,這是一道大資料處理的演算法的經典面試題,以前也經常碰到,用到的是mmap的知識,了解過,但是沒有自己實際去寫過。趁這個機會,就再一次回顧下,用swift來實現一把。
特權級, 使用者態,核心態,使用者空間,核心空間,執行緒上下文,中斷上下文, mmu等概念請參考下文
linux一些概念
mmap分析
由於指定資料的內容比較大,所以我們不能直接通過read,write的方式將大檔案直接讀入內容,因為這樣記憶體會不夠用,所以我們需要借助linux中的mmap的知識,進行記憶體對映。
mmap的工作原理,當你發起這個呼叫的時候,它只是在你的虛擬空間中分配了一段空間,連真實的實體地址都不會分配的,當你訪問這段空間,cpu陷入os核心執行異常處理,然後異常處理會在這個時間分配物理記憶體,並用檔案的內容填充這片記憶體,然後才返回你程序的上下文,這時你的程式才會感知到這片記憶體裡有資料
void *mmap(void *start,size_t length,int prot,int flags,int fd,off_t offsize);具體引數含義
length: 代表將檔案中多大的部分對映到記憶體。
prot : 對映區域的保護方式。可以為以下幾種方式的組合:
prot_exec 對映區域可被執行
prot_read 對映區域可被讀取
prot_write 對映區域可被寫入
prot_none 對映區域不能訪問
flags : 影響對映區域的各種特性。在呼叫mmap()時必須要指定
map_shared 或map_private。
map_fixed 如果引數start所指的位址無法成功建立對映時,則放棄對映,不對位址做修正。通常不鼓勵用此旗標。
map_shared 對對映區域的寫入資料會複製回檔案內,而且允許其他對映該檔案的程序共享。
map_private 對對映區域的寫入操作會產生乙個對映檔案的複製,即私人的「寫入時複製」(copy on write)對此區域作的任何修改都不會寫回原來的檔案內容。
map_anonymous建立匿名對映。此時會忽略引數fd,不涉及檔案,而且對映區域無法和其他程序共享。
map_denywrite只允許對對映區域的寫入操作,其他對檔案直接寫入的操作將會被拒絕。
map_locked 將對映區域鎖定住,這表示該區域不會被置換(swap)。
fd : 要對映到記憶體中的檔案描述符。如果使用匿名記憶體對映時,即flags中設定了map_anonymous,fd設為-1。有些系統不支援匿名記憶體對映,則可以使用fopen開啟/dev/zero檔案,
然後對該檔案進行對映,可以同樣達到匿名記憶體對映的效果。
offset:檔案對映的偏移量,通常設定為0,代表從檔案最前方開始對應,offset必須是page_size的整數倍。
複製**
錯誤**: ebadf 引數fd 不是有效的檔案描述詞 eacces 訪問許可權有誤。如果是map_private 情況下檔案必須可讀,使用map_shared則要有prot_write以及該檔案要能寫入。 einval 引數start、length 或offset有乙個不合法。 eagain 檔案被鎖住,或是有太多記憶體被鎖住。 enomem 記憶體不足。
使用者層的呼叫很簡單,其具體功能就是直接將物理記憶體直接對映到使用者虛擬記憶體,使使用者空間可以直接對物理空間操作。但是對於核心層而言,其具體實現比較複雜。
通過mmap對映出來的記憶體,通過munmap來解除對映關係
int munmap( void * addr, size_t len )在程序位址空間中解除乙個對映關係,當對映關係解除後,對原來對映位址的訪問將導致段錯誤發生。
size_t len :對映區的大小
複製**
int msync ( void * addr , size_t len, int flags)一般說來,程序在對映空間的對共享內容的改變並不直接寫回到磁碟檔案中,往往在呼叫munmap()後才執行該操作。可以呼叫msync()實現磁碟上檔案與共享記憶體區的內容一致。
size_t len :對映區的大小
int flags :ms_asyn: 非同步寫,ms_syn : 同步寫,ms_invalidat : 無效的cache 資料。
複製**
具體**如下
func
handlefile()
let leftbuf = malloc(int(leftsize))
memcpy(leftbuf, leftpart, int(leftsize))
var data = data.init(bytes: leftbuf!, count: int(leftsize))
data.reverse()
fhout?.write(data)
fhout?.synchronizefile()
munmap(leftpart, int(leftsize))
free(leftbuf)
print("剩餘部分寫入成功")
// 多執行緒處理大小的記憶體,加快處理速度
let queue = operationqueue.init()
queue.maxconcurrentoperationcount = 5
// 設定最大併發數,執行緒太多,因為執行緒切換,速度反而也降低
// 使用訊號量,防止資源寫入的時候,多執行緒seek檔案的問題
let semaphore = dispatchsemaphore.init(value: 1)
// 從第0到count段資料,分別寫入檔案的相應位置
for i in
0..let buf = malloc(int(mem_size))
memcpy(buf, part, int(mem_size))
var data = data.init(bytes: buf!, count: int(mem_size))
data.reverse()
free(buf)
semaphore.wait() // 搶占訊號資源
fhout?.seek(tofileoffset: leftsize + mem_size * (count - i - 1))
fhout?.write(data)
fhout?.synchronizefile()
semaphore.signal() // 釋放訊號資源
munmap(part, int(mem_size))
print("操作成功 i= \(i)")}}
//等佇列中所有操作結束,才能執行後面的close控制代碼的操作
queue.waituntilalloperationsarefinished()
fhin?.closefile()
fhout?.closefile()
}複製**
如何將乙個PHP陣列有格式的寫入檔案中
如何將 array k1 v1,k2 v2 這個陣列寫入乙個檔案,檔案裡面的內容和下面這種格式基本一致 array k1 v1,k2 v2 不要和我說一行行寫,有沒有快捷一點的方法?鏈結cuimingda 22 2012年11月18日提問 得票數時間先後 0贊踩採納 file put content...
python 如何將字典值寫入乙個文字檔案?
我有乙個字典,我打算把它寫入乙個檔案。exdict with open file.txt r as file file write exdict 我遇到了這樣的錯誤 file write exdict typeerror must be str not dict我修復了剛才的錯誤 exdict wi...
如何將多個excel檔案合成乙個檔案
1.需要把多個excel表都放在同乙個資料夾裡面,並在這個資料夾裡面新建乙個excel。2.用microsoft excel開啟新建的excel表,並右鍵單擊sheet1,找到 檢視 單擊進去。進去之後就看到了巨集計算介面。3.然後把下面這些巨集計算的 複製進去,然後找到 工具欄上面的 執行 下的 ...