2016-07-31 31 views
0

C++ Code:Warum ist die Verwendung des Python mmap-Moduls viel langsamer als der Aufruf von POSIX mmap aus C++?

#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-Code:

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) 

Ich denke, diese beiden Programme sind die im Wesentlichen gleich, da C++ und Python den gleichen Systemaufruf (mmap) nennen.

Aber die Python-Version ist viel langsamer als C++ 's:

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

Könnte jemand den Grund erklären Sie bitte, warum der mmap Python von viel langsamer als C++ ist?


Environment:

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

Was ist die Ausführungszeit für das gleiche Programm mit leeren 'für i in xrange (Größe): x ++' Schleife? – deniss

Antwort

6

Nicht mmap ist langsamer, aber die Füllung eines Array mit Werten. Python ist dafür bekannt, primitive Operationen langsam auszuführen. Verwenden Sie übergeordnete Operationen:

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

Wow, es endet in '0,111s'. Wirklich danke! – Sayakiss

1

Um dies näher auszuführen, was @ Daniel sagte - jeder Python Betrieb mehr Overhead hat (in einigen Fällen Weise mehr, wie Größenordnung) als die vergleichbare Menge an Code Implementierung eine Lösung in C++.

Die Schleife des Puffers Füllung ist in der Tat der Täter - sondern auch das mmap Modul selbst viel mehr Housekeeping, als Sie denken, trotz vielleicht zu tun hat, dass sie eine Schnittstelle, deren Semantik bieten, misleadingly, seeehr eng ausgerichtet mit POSIX mmap() . Sie wissen, wie POSIX mmap() wirft Sie einfach eine void* (die Sie nur munmap() verwenden müssen, um danach aufzuräumen, irgendwann)? Python's Struktur eine PyObject Struktur zu babysit void* passen - so dass es Python-Puffer-Protokoll entsprechen, durch Bereitstellung von Metadaten und Callbacks für die Laufzeit, propagieren und Warteschlangen lesen und schreiben, Aufrechterhaltung GIL-Zustand, Aufräumen seiner Zuweisungen, egal welche Fehler auftreten ...

All das Zeug braucht auch Zeit und Gedächtnis. Ich selbst benutze nie das mmap Modul, da es keinen klaren Vorteil für irgendein I/O Problem gibt, wie es von Anfang an möglich ist - Sie können genauso einfach mmap verwenden Dinge langsamer, als Sie sie schneller machen könnten.

Contrastingly oft ich * tun * feststellen, dass unter Verwendung von POSIXmmap()kann sehr vorteilhaft sein, wenn aus einem Python C/C++ Erweiterung I/O zu tun (sofern Sie den GIL Zustand sind zu kümmern), gerade weil Codierung ummmap()vermeidet all diese Python-Interne-Infrastruktur-Zeug an erster Stelle.