2016-07-31 33 views
0

C++代碼:爲什麼使用Python mmap模塊比從C++調用POSIX mmap要慢得多?

#include <string> 
#include <fcntl.h> 
#include <sys/mman.h> 
#include <unistd.h> 
#include <sys/time.h> 

using namespace std; 
#define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) 

int main() { 
    timeval tv1, tv2, tv3, tve; 
    gettimeofday(&tv1, 0); 
    int size = 0x1000000; 
    int fd = open("data", O_RDWR | O_CREAT | O_TRUNC, FILE_MODE); 
    ftruncate(fd, size); 
    char *data = (char *) mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 
    for(int i = 0; i < size; i++) { 
     data[i] = 'S'; 
    } 
    munmap(data, size); 
    close(fd); 
    gettimeofday(&tv2, 0); 
    timersub(&tv2, &tv1, &tve); 
    printf("Time elapsed: %ld.%06lds\n", (long int) tve.tv_sec, (long int) tve.tv_usec); 
} 

Python代碼:

import mmap 
import time 

t1 = time.time() 
size = 0x1000000 

f = open('data/data', 'w+') 
f.truncate(size) 
f.close() 

file = open('data/data', 'r+b') 
buffer = mmap.mmap(file.fileno(), 0) 

for i in xrange(size): 
    buffer[i] = 'S' 

buffer.close() 
file.close() 
t2 = time.time() 
print "Time elapsed: %.3fs" % (t2 - t1) 

我認爲這兩個程序是因爲C中的基本上相同++和Python調用相同的系統調用(mmap)。

但是Python版本比C++的要慢得多:

Python: Time elapsed: 1.981s 
C++: Time elapsed: 0.062143s 

可以在任何一個請說明理由的MMAP Python是比C++慢很多?


環境:

C++:

$ c++ --version 
Apple LLVM version 7.3.0 (clang-703.0.31) 
Target: x86_64-apple-darwin15.5.0 

的Python:

$ python --version 
Python 2.7.11 :: Anaconda 4.0.0 (x86_64) 
+1

相同程序的執行時間是多少?xrange(size):x ++'loop? – deniss

回答

6

mmap較慢,但具有值的陣列的填充。 Python是已知的,在做原始操作時會很慢。使用更高級別的操作:

buffer[:] = 'S' * size 
+1

哇,它以'0.111s'結尾。真的感謝! – Sayakiss

1

要闡述什麼@Daniel說 - 任何Python的操作有更多的開銷(在某些情況下方式更多,像數量級),比代碼的相當量實施解決方案在C++中。

循環填充緩衝的確是罪魁禍首 - 也是mmap模塊本身有很多家政,做的比你想象的,儘管它提供其語義的接口,誤導,verrrry密切與POSIX mmap()對齊。你知道POSIX mmap()只是拋開你一個void*(你只需要使用munmap()來清理它,在某些時候)? Python的mmap必須分配一個PyObject結構來保存void* - 通過向運行時提供元數據和回調,傳播和排隊讀寫操作,保持GIL狀態,清理其分配,無論發生什麼錯誤,都符合Python的緩衝協議。

所有這些東西都需要時間和記憶。我個人從未發現自己使用mmap模塊,因爲它不會爲任何I/O問題提供明確的優勢,例如開箱即用 - 您可以輕鬆使用mmap來製作事情慢一些,你可能會讓它們變得更快。

與此相反,我經常*做*發現使用POSIXmmap()從Python的C/C++的擴展(前提是你照看GIL狀態)內執行I/O的時候,恰恰是因爲編碼周圍可以是非常有利mmap()首先避免了所有Python內部基礎設施的東西。