2016-07-31 1 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 --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++で。

バッファを埋めるループは確かに犯人である - だけでなく、それは誤解を招く、verrrry密接POSIXに合わせ、そのセマンティクスあるインターフェースを提供することにもかかわらず、mmapモジュール自体は、あなたが思っているよりやるべきことがたくさんより多くのハウスキーピングがありmmap() 。あなたは、POSIX mmap()はあなたに(あなただけのいくつかの点で、それの後にクリーンアップするmunmap()を使用する必要があります)void*を投げる方法を知っていますか? Pythonのmmapが子守しPyObject構造を割り当てなければならないvoid* - それが伝播するとキューイングを読み取って、GILの状態を維持することに関係なく、エラーが発生したものをその割り当てをクリーンアップしない、書き込み、実行時にメタデータとコールバックを家具でPythonのバッファプロトコルに準拠すること...

その原料のすべてが、あまりにも、時間とメモリを取ります。私は個人的にはmmapモジュールを使用して自分自身を見つけることはありません。それは、あなたがすぐに使用できるようなI/O問題の明確な利点を与えないためです。mmapを簡単に使用することができますあなたはそれらをより速くするかもしれないので、物事は遅くなります。

対照的に、私はしばしば* *(あなたはGILの状態を気にしている提供)PythonのC/C++の拡張機能の中から、I/Oを行うときPOSIXmmap()を使用して正確に周りのコーディングので、非常に有利であることができることを見つけるのですかmmap()は、最初にPythonの内部インフラストラクチャをすべて避けています。

関連する問題