2016-07-31 108 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内部基础设施的东西。